update m32r port
authormeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 28 Apr 1998 05:58:21 +0000 (05:58 +0000)
committermeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 28 Apr 1998 05:58:21 +0000 (05:58 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@19465 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/m32r/m32r.c
gcc/config/m32r/m32r.h
gcc/config/m32r/m32r.md
gcc/config/m32r/t-m32r
gcc/configure
gcc/configure.in

index d9e7a7f..5c1fd17 100644 (file)
@@ -1,3 +1,60 @@
+Tue Apr 28 08:55:26 1998  Michael Meissner  <meissner@cygnus.com>
+
+       * m32r.c (*_oper{and|ator}): Change enum arguments and return
+       values to int, so they can be prototyped even in files that don't
+       include rtl.h.
+       ({small,large}_insn_p): Ditto.
+       (m32r_select_cc_mode): Ditto.
+       (gen_compare): Ditto.
+       (function_arg_partial_nregs): Ditto.
+       (m32r_setup_incoming_varargs): Ditto.
+       (init_reg_tables): Add prototype.
+       (m32r_frame_info): Add prolog_size field.
+       (m32r_compute_frame_size): Calculate the size of the prologue.
+       (m32r_first_insn_address): Return prologue size.
+       (m32r_output_function_prologue): Calculate frame size before
+       printing out information.  Print out the prologue size.
+
+       * m32r.h: Prototype all functions in m32r.c.
+       (FIRST_INSN_ADDRESS): Declare, returning prologue size.
+
+       * m32r.md (bcc functions): Cast enum's to int.
+
+       * m32r.c (conditional_move_operand): Silence a debug message.
+       ({small,long}_insn): New predicates.
+       
+       * m32r.h (TARGET_M32R): New macro.
+       (PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn.
+       (HAIFA_P): Define as 1/0 depending on whether the Haifa scheduler
+       was selected.
+       (ISSUE_RATE): Define as 2.
+
+       * m32r.md (insn_size): New attribute.
+       ({,rev_}branch_insn): Add .s qualifier to branches believed to be
+       short.
+       (m32r): New attribute.
+
+       * configure.in (enable_haifa): Switch m32r to Haifa by default.
+       * configure: Regenerate.
+
+       (Changes from Nick Clifton <nickc@cygnus.com>)
+       * m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint to perfoirm
+       the equivalent of a negated 'I' constraint.
+       (PRESERVE_DEATH_INFO_REGNO_P): Define in order to allow peephole
+       optimisation to work.
+
+       * m32r.md (cmp_ne_small_const_insn): Use 'S' constriant rather
+       than 'I' since the value is negated.
+       (peephole): Add peephole optimisation to cope with optimization of
+       divide and subtracts of the same operands.
+
+       * m32r.c zero_and_one, emit_cond_move): Add support for MVFC.
+       * m32r.h: Ditto. 
+       * m32r.md: Ditto.
+
+       * m32r.h (PREDICATE_CODES): Add declaration of machine specific
+       predicates.
+
 Tue Apr 28 07:25:53 1998  Manfred Hollstein  <manfred@s-direktnet.de>
 
        * Makefile.in (libgcc2.ready): Revert last patch (Apr 24).
index 0b7b631..3f80057 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used for code generation on the Mitsubishi M32R cpu.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -41,8 +41,6 @@ rtx m32r_compare_op0, m32r_compare_op1;
 /* Array of valid operand punctuation characters.  */
 char m32r_punct_chars[256];
 
-static void init_reg_tables ();
-
 /* Selected code model.  */
 char *m32r_model_string = M32R_MODEL_DEFAULT;
 enum m32r_model m32r_model;
@@ -51,6 +49,10 @@ enum m32r_model m32r_model;
 char *m32r_sdata_string = M32R_SDATA_DEFAULT;
 enum m32r_sdata m32r_sdata;
 
+
+/* Forward declaration.  */
+static void init_reg_tables    PROTO((void));
+
 /* Called by OVERRIDE_OPTIONS to initialize various things.  */
 
 void
@@ -84,6 +86,7 @@ m32r_init ()
     m32r_sdata = M32R_SDATA_USE;
   else
     error ("bad value (%s) for -msdata switch", m32r_sdata_string);
+
 }
 
 /* Vectors to keep interesting information about registers where it can easily
@@ -95,7 +98,8 @@ m32r_init ()
    they all fit (as bit numbers) in a 32 bit word (again).  Each real mode is
    mapped into one m32r_mode_class mode.  */
 
-enum m32r_mode_class {
+enum m32r_mode_class
+{
   C_MODE,
   S_MODE, D_MODE, T_MODE, O_MODE,
   SF_MODE, DF_MODE, TF_MODE, OF_MODE
@@ -113,9 +117,11 @@ enum m32r_mode_class {
 /* Modes for quad-word and smaller quantities.  */
 #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
 
+
 /* Value is 1 if register/mode pair is acceptable on arc.  */
 
-unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] = {
+unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] =
+{
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,
   S_MODES, C_MODES
@@ -412,21 +418,23 @@ m32r_init_expanders ()
 /* Acceptable arguments to the call insn.  */
 
 int
-call_address_operand (op, mode)
+call_address_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
-  return symbolic_operand (op, mode);
+  return symbolic_operand (op, int_mode);
 
-  /* Constants and values in registers are not OK, because
-     the m32r BL instruction can only support PC relative branching.  */ 
+/* Constants and values in registers are not OK, because
+   the m32r BL instruction can only support PC relative branching.  */ 
 }
 
 int
-call_operand (op, mode)
+call_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
+
   if (GET_CODE (op) != MEM)
     return 0;
   op = XEXP (op, 0);
@@ -436,9 +444,9 @@ call_operand (op, mode)
 /* Returns 1 if OP is a symbol reference.  */
 
 int
-symbolic_operand (op, mode)
+symbolic_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   switch (GET_CODE (op))
     {
@@ -446,6 +454,7 @@ symbolic_operand (op, mode)
     case LABEL_REF:
     case CONST :
       return 1;
+
     default:
       return 0;
     }
@@ -454,9 +463,9 @@ symbolic_operand (op, mode)
 /* Return 1 if OP is a reference to an object in .sdata/.sbss.  */
 
 int
-small_data_operand (op, mode)
+small_data_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (! TARGET_SDATA_USE)
     return 0;
@@ -477,9 +486,9 @@ small_data_operand (op, mode)
 /* Return 1 if OP is a symbol that can use 24 bit addressing.  */
 
 int
-addr24_operand (op, mode)
+addr24_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) == LABEL_REF)
     return TARGET_ADDR24;
@@ -509,24 +518,24 @@ addr24_operand (op, mode)
 /* Return 1 if OP is a symbol that needs 32 bit addressing.  */
 
 int
-addr32_operand (op, mode)
+addr32_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) == LABEL_REF)
     return TARGET_ADDR32;
 
   if (GET_CODE (op) == SYMBOL_REF)
-    return (! addr24_operand (op)
-           && ! small_data_operand (op));
+    return (! addr24_operand (op, int_mode)
+           && ! small_data_operand (op, int_mode));
 
   if (GET_CODE (op) == CONST
       && GET_CODE (XEXP (op, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
       && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
     {
-      return (! addr24_operand (op)
-             && ! small_data_operand (op));
+      return (! addr24_operand (op, int_mode)
+             && ! small_data_operand (op, int_mode));
     }
 
   return 0;
@@ -535,9 +544,9 @@ addr32_operand (op, mode)
 /* Return 1 if OP is a function that can be called with the `bl' insn.  */
 
 int
-call26_operand (op, mode)
+call26_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) == SYMBOL_REF)
     return ! LARGE_NAME_P (XSTR (op, 0));
@@ -548,9 +557,9 @@ call26_operand (op, mode)
 /* Returns 1 if OP is an acceptable operand for seth/add3.  */
 
 int
-seth_add3_operand (op, mode)
+seth_add3_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) == SYMBOL_REF
       || GET_CODE (op) == LABEL_REF)
@@ -570,9 +579,9 @@ seth_add3_operand (op, mode)
    useful in comparisons.  */
 
 int
-cmp_int16_operand (op, mode)
+cmp_int16_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -581,10 +590,10 @@ cmp_int16_operand (op, mode)
 
 /* Return true if OP is an unsigned 16 bit immediate value.  */
 
-static int
-uint16_operand (op, mode)
+int
+uint16_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -594,10 +603,12 @@ uint16_operand (op, mode)
 /* Return true if OP is a register or signed 8 bit value.  */
 
 int
-reg_or_int16_operand (op, mode)
+reg_or_int16_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
+
   if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
     return register_operand (op, mode);
   if (GET_CODE (op) != CONST_INT)
@@ -608,10 +619,12 @@ reg_or_int16_operand (op, mode)
 /* Return true if OP is a register or an unsigned 16 bit value.  */
 
 int
-reg_or_uint16_operand (op, mode)
+reg_or_uint16_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
+
   if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
     return register_operand (op, mode);
   if (GET_CODE (op) != CONST_INT)
@@ -622,10 +635,12 @@ reg_or_uint16_operand (op, mode)
 /* Return true if OP is a register or signed 16 bit value for compares.  */
 
 int
-reg_or_cmp_int16_operand (op, mode)
+reg_or_cmp_int16_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
+
   if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
     return register_operand (op, mode);
   if (GET_CODE (op) != CONST_INT)
@@ -636,9 +651,9 @@ reg_or_cmp_int16_operand (op, mode)
 /* Return true if OP is a const_int requiring two instructions to load.  */
 
 int
-two_insn_const_operand (op, mode)
+two_insn_const_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -653,15 +668,16 @@ two_insn_const_operand (op, mode)
    move source.  */
 
 int
-move_src_operand (op, mode)
+move_src_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
   switch (GET_CODE (op))
     {
     case SYMBOL_REF :
     case CONST :
-      return addr24_operand (op, mode);
+      return addr24_operand (op, int_mode);
     case CONST_INT :
       /* ??? We allow more cse opportunities if we only allow constants
         loadable with one insn, and split the rest into two.  The instances
@@ -704,10 +720,11 @@ move_src_operand (op, mode)
    move source.  */
 
 int
-move_double_src_operand (op, mode)
+move_double_src_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
   switch (GET_CODE (op))
     {
     case CONST_INT :
@@ -722,7 +739,7 @@ move_double_src_operand (op, mode)
       /* (subreg (mem ...) ...) can occur here if the inner part was once a
         pseudo-reg and is now a stack slot.  */
       if (GET_CODE (SUBREG_REG (op)) == MEM)
-       return move_double_src_operand (SUBREG_REG (op), mode);
+       return move_double_src_operand (SUBREG_REG (op), int_mode);
       else
        return register_operand (op, mode);
     case MEM :
@@ -739,10 +756,11 @@ move_double_src_operand (op, mode)
 /* Return true if OP is an acceptable argument for a move destination.  */
 
 int
-move_dest_operand (op, mode)
+move_dest_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
   switch (GET_CODE (op))
     {
     case REG :
@@ -805,9 +823,9 @@ easy_df_const (op)
 /* Return 1 if OP is an EQ or NE comparison operator.  */
 
 int
-eqne_comparison_operator (op, mode)
+eqne_comparison_operator (op, int_mode)
     rtx op;
-    enum machine_mode mode;
+    int int_mode;
 {
   enum rtx_code code = GET_CODE (op);
 
@@ -819,9 +837,9 @@ eqne_comparison_operator (op, mode)
 /* Return 1 if OP is a signed comparison operator.  */
 
 int
-signed_comparison_operator (op, mode)
+signed_comparison_operator (op, int_mode)
     rtx op;
-    enum machine_mode mode;
+    int int_mode;
 {
   enum rtx_code code = GET_CODE (op);
 
@@ -835,35 +853,70 @@ signed_comparison_operator (op, mode)
    This is used in insn length calcs.  */
 
 int
-memreg_operand (op, mode)
+memreg_operand (op, int_mode)
      rtx op;
-     enum machine_mode mode;
+     int int_mode;
 {
   return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG;
 }
+
+/* Return non-zero if the operand is an insn that is a small insn.
+   Allow const_int 0 as well, which is a placeholder for NOP slots.  */
+
+int
+small_insn_p (op, int_mode)
+     rtx op;
+     int int_mode;
+{
+  if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+    return 1;
+
+  if (GET_RTX_CLASS (GET_CODE (op)) != 'i')
+    return 0;
+
+  return get_attr_length (op) == 2;
+}
+
+/* Return non-zero if the operand is an insn that is a large insn.  */
+
+int
+large_insn_p (op, int_mode)
+     rtx op;
+     int int_mode;
+{
+  if (GET_RTX_CLASS (GET_CODE (op)) != 'i')
+    return 0;
+
+  return get_attr_length (op) != 2;
+}
+
 \f
 /* Comparisons.  */
 
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  */
 
-enum machine_mode
+int
 m32r_select_cc_mode (op, x, y)
-     enum rtx_code op;
+     int op;
      rtx x, y;
 {
-  return CCmode;
+  return (int)CCmode;
 }
 
 /* X and Y are two things to compare using CODE.  Emit the compare insn and
-   return the rtx for compare [arg0 of the if_then_else].  */
+   return the rtx for compare [arg0 of the if_then_else].
+   If need_compare is true then the comparison insn must be generated, rather
+   than being susummed into the following branch instruction. */
 
 rtx
-gen_compare (code, x, y)
-     enum rtx_code code;
+gen_compare (int_code, x, y, need_compare)
+     int          int_code;
      rtx           x;
      rtx           y;
+     int           need_compare;
 {
+  enum rtx_code     code = (enum rtx_code)int_code;
   enum rtx_code     compare_code;
   enum rtx_code     branch_code;
   enum machine_mode mode      = SELECT_CC_MODE (code, x, y);
@@ -884,7 +937,122 @@ gen_compare (code, x, y)
     case GEU: compare_code = LTU; branch_code = EQ; break;
     }
 
-  if (! TARGET_OLD_COMPARE)
+  if (need_compare)
+    {
+      switch (compare_code)
+       {
+       case EQ:
+         if (GET_CODE (y) == CONST_INT
+             && CMP_INT16_P (INTVAL (y))               /* reg equal to small const.  */
+             && y != const0_rtx)
+           {
+             rtx tmp = gen_reg_rtx (SImode);           
+             
+             emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y));
+             x = tmp;
+             y = const0_rtx;
+           }
+         else if (CONSTANT_P (y))                      /* reg equal to const.  */
+           {
+             rtx tmp = force_reg (GET_MODE (x), y);
+             y = tmp;
+           }
+
+         if (register_operand (y, SImode)              /* reg equal to reg.  */
+             || y == const0_rtx)                       /* req equal to zero. */
+           {
+               emit_insn (gen_cmp_eqsi_insn (x, y));
+               
+             return gen_rtx (code, mode, cc_reg, const0_rtx);
+           }
+         break;
+      
+       case LT:
+         if (register_operand (y, SImode)
+             || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
+           {
+             rtx tmp = gen_reg_rtx (SImode);         /* reg compared to reg. */
+             
+             switch (code)
+               {
+               case LT:
+                 emit_insn (gen_cmp_ltsi_insn (x, y));
+                 code = EQ;
+                 break;
+               case LE:
+                 if (y == const0_rtx)
+                   tmp = const1_rtx;
+                 else
+                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                 emit_insn (gen_cmp_ltsi_insn (x, tmp));
+                 code = EQ;
+                 break;
+               case GT:
+                 if (GET_CODE (y) == CONST_INT)
+                   tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+                 else
+                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                 emit_insn (gen_cmp_ltsi_insn (x, tmp));
+                 code = NE;
+                 break;
+               case GE:
+                 emit_insn (gen_cmp_ltsi_insn (x, y));
+                 code = NE;
+                 break;
+               default:
+                 abort();
+               }
+             
+             return gen_rtx (code, mode, cc_reg, const0_rtx);
+           }
+         break;
+         
+       case LTU:
+         if (register_operand (y, SImode)
+             || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
+           {
+             rtx tmp = gen_reg_rtx (SImode);         /* reg (unsigned) compared to reg. */
+             
+             switch (code)
+               {
+               case LTU:
+                 emit_insn (gen_cmp_ltusi_insn (x, y));
+                 code = EQ;
+                 break;
+               case LEU:
+                 if (y == const0_rtx)
+                   tmp = const1_rtx;
+                 else
+                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                 emit_insn (gen_cmp_ltusi_insn (x, tmp));
+                 code = EQ;
+                 break;
+               case GTU:
+                 if (GET_CODE (y) == CONST_INT)
+                   tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+                 else
+                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                 emit_insn (gen_cmp_ltusi_insn (x, tmp));
+                 code = NE;
+                 break;
+               case GEU:
+                 emit_insn (gen_cmp_ltusi_insn (x, y));
+                 code = NE;
+                 break;
+               default:
+                 abort();
+               }
+             
+             return gen_rtx (code, mode, cc_reg, const0_rtx);
+           }
+         break;
+
+       default:
+         abort();
+       }
+    }
+  else
+    if (! TARGET_OLD_COMPARE)
     {
       /* reg/reg equal comparison */
       if (compare_code == EQ
@@ -950,12 +1118,13 @@ gen_compare (code, x, y)
 /* Implements the FUNCTION_ARG_PARTIAL_NREGS macro.  */
 
 int
-function_arg_partial_nregs (cum, mode, type, named)
+function_arg_partial_nregs (cum, int_mode, type, named)
      CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
+     int int_mode;
      tree type;
      int named;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
   int ret;
   int size = (((mode == BLKmode && type)
               ? int_size_in_bytes (type)
@@ -979,13 +1148,14 @@ function_arg_partial_nregs (cum, mode, type, named)
    and mode MODE, and we rely on this fact.  */
 
 void
-m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+m32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl)
      CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
+     int int_mode;
      tree type;
      int *pretend_size;
      int no_rtl;
 {
+  enum machine_mode mode = (enum machine_mode)int_mode;
   int first_anon_arg;
 
   if (no_rtl)
@@ -1128,6 +1298,7 @@ struct m32r_frame_info
   unsigned int args_size;      /* # bytes that outgoing arguments take up */
   unsigned int reg_size;       /* # bytes needed to store regs */
   unsigned int var_size;       /* # bytes that variables take up */
+  unsigned int prolog_size;    /* # bytes that the prologue takes up */
   unsigned int gmask;          /* mask of saved gp registers */
   unsigned int save_fp;                /* nonzero if fp must be saved */
   unsigned int save_lr;                /* nonzero if lr (return addr) must be saved */
@@ -1153,6 +1324,9 @@ static struct m32r_frame_info zero_frame_info;
 #define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
 #define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
 
+#define SHORT_INSN_SIZE 2      /* size of small instructions */
+#define LONG_INSN_SIZE 4       /* size of long instructions */
+
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.
 
@@ -1164,7 +1338,7 @@ m32r_compute_frame_size (size)
 {
   int regno;
   unsigned int total_size, var_size, args_size, pretend_size, extra_size;
-  unsigned int reg_size;
+  unsigned int reg_size, prolog_size, frame_size;
   unsigned int gmask;
   enum m32r_function_type fn_type;
   int interrupt_p;
@@ -1175,6 +1349,7 @@ m32r_compute_frame_size (size)
   extra_size   = FIRST_PARM_OFFSET (0);
   total_size   = extra_size + pretend_size + args_size + var_size;
   reg_size     = 0;
+  prolog_size  = 0;
   gmask                = 0;
 
   /* See if this is an interrupt handler.  Call used registers must be saved
@@ -1204,6 +1379,33 @@ m32r_compute_frame_size (size)
      handler will do the right thing if this changes total_size.  */
   total_size = M32R_STACK_ALIGN (total_size);
 
+  /* Calculate prologue size.  Obviously any changes to
+     m32r_output_function_prologue must be mirrored here.  */
+  if (pretend_size)
+    prolog_size += SHORT_INSN_SIZE;            /* addi sp,-pretend_size */
+
+  prolog_size += SHORT_INSN_SIZE * (reg_size / UNITS_PER_WORD);        /* pushes */
+  frame_size = total_size - (pretend_size + reg_size);
+
+  if (frame_size == 0)
+    ;                                          /* nothing to do */
+  else if (frame_size <= 128)
+    prolog_size += SHORT_INSN_SIZE;            /* addi sp,-<frame> */
+  else
+    {
+      if ((prolog_size % LONG_INSN_SIZE) != 0)
+       prolog_size += SHORT_INSN_SIZE;         /* nop */
+
+      if (frame_size <= 32768)
+       prolog_size += LONG_INSN_SIZE;          /* add3 sp,sp,-<frame> */
+      else
+       prolog_size += (LONG_INSN_SIZE          /* ld24 tmp,<frame>/sub sp,tmp */
+                       + SHORT_INSN_SIZE);
+    }
+
+  if (frame_pointer_needed)
+    prolog_size += SHORT_INSN_SIZE;            /* mv fp,sp */
+
   /* Save computed information.  */
   current_frame_info.total_size   = total_size;
   current_frame_info.extra_size   = extra_size;
@@ -1211,6 +1413,7 @@ m32r_compute_frame_size (size)
   current_frame_info.var_size     = var_size;
   current_frame_info.args_size    = args_size;
   current_frame_info.reg_size    = reg_size;
+  current_frame_info.prolog_size  = prolog_size;
   current_frame_info.gmask       = gmask;
   current_frame_info.initialized  = reload_completed;
 
@@ -1218,7 +1421,22 @@ m32r_compute_frame_size (size)
   return total_size;
 }
 \f
-/* Set up the stack and frame pointer (if desired) for the function.  */
+/* When the `length' insn attribute is used, this macro specifies the
+   value to be assigned to the address of the first insn in a
+   function.  If not specified, 0 is used.  */
+
+int
+m32r_first_insn_address ()
+{
+  if (! current_frame_info.initialized)
+    m32r_compute_frame_size (get_frame_size ());
+
+  return current_frame_info.prolog_size;
+}
+\f
+/* Set up the stack and frame pointer (if desired) for the function.
+   Note, if this is changed, you need to mirror the changes in
+   m32r_compute_frame_size which calculates the prolog size.  */
 
 void
 m32r_output_function_prologue (file, size)
@@ -1239,17 +1457,19 @@ m32r_output_function_prologue (file, size)
               ASM_COMMENT_START);
     }
 
+  total_size = (! current_frame_info.initialized
+               ? m32r_compute_frame_size (size)
+               : current_frame_info.total_size);
+
   /* This is only for the human reader.  */
-  fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n",
-          ASM_COMMENT_START, ASM_COMMENT_START,
+  fprintf (file,
+          "\t%s BEGIN PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d, prolog= %d\n",
+          ASM_COMMENT_START,
           current_frame_info.var_size,
           current_frame_info.reg_size / 4,
           current_frame_info.args_size,
-          current_frame_info.extra_size);
-
-  total_size = (! current_frame_info.initialized
-               ? m32r_compute_frame_size (size)
-               : current_frame_info.total_size);
+          current_frame_info.extra_size,
+          current_frame_info.prolog_size);
 
   /* These cases shouldn't happen.  Catch them now.  */
   if (total_size == 0 && gmask)
@@ -1767,3 +1987,127 @@ m32r_print_operand_address (file, addr)
       break;
     }
 }
+
+/* Return true if the operands are the constants 0 and 1.  */
+int
+zero_and_one (operand1, operand2)
+     rtx operand1;
+     rtx operand2;
+{
+  return
+       GET_CODE (operand1) == CONST_INT
+    && GET_CODE (operand2) == CONST_INT
+    && (  ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1))
+       ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));
+}
+
+/* Return non-zero if the operand is suitable for use in a conditional move sequence.  */
+int
+conditional_move_operand (operand, int_mode)
+     rtx operand;
+     int int_mode;
+{
+  enum machine_mode mode = (enum machine_mode)int_mode;
+
+  /* Only defined for simple integers so far... */
+  if (mode != SImode && mode != HImode && mode != QImode)
+    return FALSE;
+
+  /* At the moment we can hanndle moving registers and loading constants.  */
+  /* To be added: Addition/subtraction/bitops/multiplication of registers.  */
+
+  switch (GET_CODE (operand))
+    {
+    case REG:
+      return 1;
+
+    case CONST_INT:
+      return INT8_P (INTVAL (operand));
+
+    default:
+#if 0
+      fprintf (stderr, "Test for cond move op of type: %s\n",
+              GET_RTX_NAME (GET_CODE (operand)));
+#endif
+      return 0;
+    }
+}
+
+/* Return true if the code is a test of the carry bit */
+int
+carry_compare_operand (op, int_mode)
+     rtx op;
+     int int_mode;
+{
+  rtx x;
+
+  if (GET_MODE (op) != CCmode && GET_MODE (op) != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) != NE && GET_CODE (op) != EQ)
+    return FALSE;
+
+  x = XEXP (op, 0);
+  if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM)
+    return FALSE;
+
+  x = XEXP (op, 1);
+  if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/* Generate the correct assembler code to handle the conditional loading of a
+   value into a register.  It is known that the operands satisfy the
+   conditional_move_operand() function above.  The destination is operand[0].
+   The condition is operand [1].  The 'true' value is operand [2] and the
+   'false' value is operand [3].  */
+char *
+emit_cond_move (operands, insn)
+     rtx * operands;
+     rtx   insn;
+{
+  static char buffer [100];
+
+  buffer [0] = 0;
+  
+  /* Destination must be a register.  */
+  if (GET_CODE (operands [0]) != REG)
+    abort();
+  if (! conditional_move_operand (operands [2], SImode))
+    abort();
+  if (! conditional_move_operand (operands [3], SImode))
+    abort();
+      
+
+  /* Check to see if the test is reversed.  */
+  if (GET_CODE (operands [1]) == NE)
+    {
+      rtx tmp = operands [2];
+      operands [2] = operands [3];
+      operands [3] = tmp;
+    }
+
+  /* Catch a special case where 0 or 1 is being loaded into the destination.
+     Since we already have these values in the C bit we can use a special
+     instruction.  */
+  if (zero_and_one (operands [2], operands [3]))
+    {
+      char * dest = reg_names [REGNO (operands [0])];
+      
+      sprintf (buffer, "mvfc %s, cbr", dest);
+
+      /* If the true value was '0' then we need to invert the results of the move.  */
+      if (INTVAL (operands [2]) == 0)
+       sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1",
+                dest, dest);
+      
+      return buffer;
+    }
+
+
+  return buffer;
+}
+
index d438b49..199f386 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions of target machine for GNU compiler, Mitsubishi M32R cpu.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA.  */
 /* Print subsidiary information on the compiler version in use.  */
 #define TARGET_VERSION fprintf (stderr, " (m32r)")
 
+
 /* Switch  Recognition by gcc.c.  Add -G xx support */
 
 #undef SWITCH_TAKES_ARG
@@ -48,17 +49,18 @@ Boston, MA 02111-1307, USA.  */
 /* __M32R__ is defined by the existing compiler so we use that.  */
 #define CPP_PREDEFINES "-Acpu(m32r) -Amachine(m32r) -D__M32R__"
 
-/* Additional flags for the preprocessor.  */
-#define CPP_SPEC ""
 
 #define CC1_SPEC "%{G*}"
 
-#undef ASM_SPEC
+/* Options to pass on to the assembler.  */
+#undef  ASM_SPEC
+#define ASM_SPEC "%{v}"
+
 #if 0 /* not supported yet */
+#undef  ASM_SPEC
 #define ASM_SPEC "%{v} %{mrelax:-relax}"
-#else
-#define ASM_SPEC "%{v}"
 #endif
+     
 
 #undef ASM_FINAL_SPEC
 
@@ -72,9 +74,11 @@ Boston, MA 02111-1307, USA.  */
 #undef STARTFILE_SPEC
 #define STARTFILE_SPEC "%{!shared:crt0.o%s crtsysc.o%s} crtinit.o%s"
 
+
 #undef ENDFILE_SPEC
 #define ENDFILE_SPEC "crtfini.o%s"
 
+     
 #undef LIB_SPEC
 \f
 /* Run-time compilation parameters selecting different hardware subsets.  */
@@ -105,6 +109,10 @@ extern int target_flags;
 #define TARGET_OLD_COMPARE_MASK 8
 #define TARGET_OLD_COMPARE (target_flags & TARGET_OLD_COMPARE_MASK)
 
+/* Target machine to compile for.  */
+#define TARGET_M32R 1
+
+
 /* Macro to define tables used to set the flags.
    This is a list in braces of pairs in braces,
    each pair being { "NAME", VALUE }
@@ -147,6 +155,8 @@ extern int target_flags;
 
 extern char *m32r_model_string;
 extern char *m32r_sdata_string;
+
+
 #define TARGET_OPTIONS \
 {                                              \
   { "model=",  &m32r_model_string      },      \
@@ -239,10 +249,10 @@ extern enum m32r_sdata m32r_sdata;
 #define M32R_SDATA_DEFAULT "none"
 
 /* Define this macro as a C expression for the initializer of an array of
-   string to tell the driver program which options are defaults for this
+   strings to tell the driver program which options are defaults for this
    target and thus do not need to be handled specially when using
    `MULTILIB_OPTIONS'.  */
-#define MULTILIB_DEFAULTS { "mmodel=small" }
+#define MULTILIB_DEFAULTS { "mmodel=small", "m32r" }
 
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
@@ -253,8 +263,6 @@ extern enum m32r_sdata m32r_sdata;
    Don't use this macro to turn on various extra optimizations for
    `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
 
-extern void m32r_init ();
-
 #define OVERRIDE_OPTIONS \
 do {                           \
   /* These need to be done at start up.  It's convenient to do them here.  */ \
@@ -404,7 +412,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT               \
    All registers that the compiler knows about must be given numbers,
    even those that are not normally considered general registers.  */
 #define FIRST_PSEUDO_REGISTER 18
-
+       
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.
 
@@ -420,6 +428,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT               \
    16    - arg pointer
    17    - carry flag
 
+   
    By default, the extension registers are not available.  */
 
 #define FIXED_REGISTERS \
@@ -427,6 +436,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT               \
   0, 0, 0, 0, 0, 0, 0, 1,      \
   1, 0 }
 
+
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
    registers that can be used without being saved.
@@ -439,6 +449,7 @@ if (GET_MODE_CLASS (MODE) == MODE_INT               \
   0, 0, 0, 0, 0, 0, 1, 1,      \
   1, 1 }
 
+
 /* Zero or more C statements that may conditionally modify two variables
    `fixed_regs' and `call_used_regs' (both of type `char []') after they
    have been initialized from the two preceding macros.
@@ -531,11 +542,12 @@ enum reg_class {
 #define REG_CLASS_CONTENTS \
 { {0}, {0x20000}, {0x1ffff}, {0x3ffff} }
 
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
    or could index an array.  */
-extern enum reg_class m32r_regno_reg_class[];
+extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
 #define REGNO_REG_CLASS(REGNO) \
 (m32r_regno_reg_class[REGNO])
 
@@ -622,7 +634,11 @@ extern enum reg_class m32r_regno_reg_class[];
    C.  If C is not defined as an extra constraint, the value returned should
    be 0 regardless of VALUE.  */
 /* Q is for symbolic addresses loadable with ld24.
-   R is for symbolic addresses when ld24 can't be used.  */
+   R is for symbolic addresses when ld24 can't be used.
+   S is for an 8 bit signed integer in the range +128 to -127 */
+
+#define INVERTED_SIGNED_8BIT(VAL) ((VAL) >= -127 && (VAL) <= 128)
+
 #define EXTRA_CONSTRAINT(VALUE, C) \
 ((C) == 'Q' \
  ? ((TARGET_ADDR24 && GET_CODE (VALUE) == LABEL_REF) \
@@ -630,6 +646,8 @@ extern enum reg_class m32r_regno_reg_class[];
  : (C) == 'R' \
  ? ((TARGET_ADDR32 && GET_CODE (VALUE) == LABEL_REF) \
     || addr32_operand (VALUE, VOIDmode)) \
+ : (C) == 'S' \
+ ?  ((GET_CODE (VALUE) == CONST_INT) && INVERTED_SIGNED_8BIT (INTVAL (VALUE))) \
  : 0)
 \f
 /* Stack layout and stack pointer usage.  */
@@ -717,6 +735,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
 #define CARRY_REGNUM 17
 #define M32R_MAX_INT_REGS 16
 
+     
 #define GPR_P(REGNO) ((unsigned) (REGNO) < M32R_MAX_INT_REGS)
 \f
 /* Eliminating the frame and arg pointers.  */
@@ -907,7 +926,7 @@ M32R_STACK_ALIGN (current_function_outgoing_args_size)
    compiler when this occurs, and how many of the words should go in
    registers.  */
 #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
-  function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)
+  function_arg_partial_nregs (&CUM, (int)MODE, TYPE, NAMED)
 
 /* A C expression that indicates when an argument must be passed by
    reference.  If nonzero for an argument, a copy of that argument is
@@ -1218,9 +1237,8 @@ do {                                      \
 
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  */
-extern enum machine_mode m32r_select_cc_mode ();
 #define SELECT_CC_MODE(OP, X, Y) \
-m32r_select_cc_mode (OP, X, Y)
+((enum machine_mode)m32r_select_cc_mode ((int)OP, X, Y))
 
 /* Return non-zero if SELECT_CC_MODE will never return MODE for a
    floating point inequality comparison.  */
@@ -1313,6 +1331,38 @@ m32r_select_cc_mode (OP, X, Y)
    the improvement wasn't significant and in a couple of cases caused a
    significant de-optimization.  */
 /* #define ENABLE_REGMOVE_PASS */
+
+/* A C statement (sans semicolon) to update the integer variable COST based on
+   the relationship between INSN that is dependent on DEP_INSN through the
+   dependence LINK.  The default is to make no adjustment to COST.  This can be
+   used for example to specify to the scheduler that an output- or
+   anti-dependence does not incur the same cost as a data-dependence.  */
+
+/* #define ADJUST_COST(INSN,LINK,DEP_INSN,COST)                                \
+  (COST) = m32r_adjust_cost (INSN, LINK, DEP_INSN, COST) */
+
+/* A C statement (sans semicolon) to update the integer scheduling
+   priority `INSN_PRIORITY(INSN)'.  Reduce the priority to execute
+   the INSN earlier, increase the priority to execute INSN later.
+   Do not define this macro if you do not need to adjust the
+   scheduling priorities of insns.  */
+/* #define ADJUST_PRIORITY (INSN) */
+
+/* Macro to determine whether the Haifa scheduler is used.  */
+#ifdef HAIFA
+#define HAIFA_P 1
+#else
+#define HAIFA_P 0
+#endif
+
+/* Indicate how many instructions can be issued at the same time.  */
+#define ISSUE_RATE 2
+
+/* When the `length' insn attribute is used, this macro specifies the
+   value to be assigned to the address of the first insn in a
+   function.  If not specified, 0 is used.  */
+#define FIRST_INSN_ADDRESS m32r_first_insn_address ()
+
 \f
 /* Section selection.  */
 
@@ -1344,7 +1394,7 @@ DTORS_SECTION_FUNCTION \
 SDATA_SECTION_FUNCTION \
 SBSS_SECTION_FUNCTION
 
-#define SDATA_SECTION_FUNCTION \
+#define SDATA_SECTION_FUNCTION                                         \
 void                                                                   \
 sdata_section ()                                                       \
 {                                                                      \
@@ -1355,7 +1405,7 @@ sdata_section ()                                                  \
     }                                                                  \
 }                                                                      \
 
-#define SBSS_SECTION_FUNCTION \
+#define SBSS_SECTION_FUNCTION                                          \
 void                                                                   \
 sbss_section ()                                                                \
 {                                                                      \
@@ -1429,7 +1479,6 @@ extern void m32r_select_section ();
  || MEDIUM_NAME_P (SYMBOL_NAME) \
  || LARGE_NAME_P (SYMBOL_NAME))
 
-extern void m32r_encode_section_info ();
 #define ENCODE_SECTION_INFO(DECL) m32r_encode_section_info (DECL)
 
 /* Decode SYM_NAME and store the real name part in VAR, sans
@@ -1487,7 +1536,6 @@ do {                                                      \
 /* Control the assembler format that we output.  */
 
 /* Output at beginning of assembler file.  */
-extern void m32r_asm_file_start ();
 #define ASM_FILE_START(FILE) m32r_asm_file_start (FILE)
 
 /* A C string constant describing how to begin a comment in the target
@@ -1582,7 +1630,7 @@ do {                              \
 #undef ASM_OUTPUT_LABELREF
 #define ASM_OUTPUT_LABELREF(FILE, NAME) \
 do {                                                   \
-  char *real_name;                                     \
+  char * real_name;                                    \
   STRIP_NAME_ENCODING (real_name, (NAME));             \
   fprintf (FILE, "%s%s", USER_LABEL_PREFIX, real_name);        \
 } while (0)           
@@ -1713,8 +1761,6 @@ do {                                                                      \
    handling the required alignment of the variable.  The alignment is
    specified as the number of bits.  */
 
-extern void sbss_section ();
-
 #undef ASM_OUTPUT_ALIGNED_LOCAL
 #define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
 do {                                                                   \
@@ -1833,35 +1879,146 @@ do {                                                                   \
 /* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
    is a valid machine specific attribute for DECL.
    The attributes in ATTRIBUTES have previously been assigned to TYPE.  */
-extern int m32r_valid_machine_attribute ();
 #define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
 m32r_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
 
 /* A C expression that returns zero if the attributes on TYPE1 and TYPE2 are
    incompatible, one if they are compatible, and two if they are
    nearly compatible (which causes a warning to be generated).  */
-extern int m32r_comp_type_attributes ();
 #define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
 m32r_comp_type_attributes (TYPE1, TYPE2)
 
 /* Give newly defined TYPE some default attributes.  */
-extern void m32r_set_default_type_attributes ();
 #define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
 m32r_set_default_type_attributes (TYPE)
 \f
 /* Define the information needed to generate branch and scc insns.  This is
    stored from the compare operation.  Note that we can't use "rtx" here
    since it hasn't been defined!  */
-extern struct rtx_def *m32r_compare_op0, *m32r_compare_op1;
-
-/* Define the function that build the compare insn for scc and bcc.  */
-extern struct rtx_def *gen_compare ();
+extern struct rtx_def * m32r_compare_op0;
+extern struct rtx_def * m32r_compare_op1;
 
 /* M32R function types.   */
-enum m32r_function_type {
+enum m32r_function_type
+{
   M32R_FUNCTION_UNKNOWN, M32R_FUNCTION_NORMAL, M32R_FUNCTION_INTERRUPT
 };
 #define M32R_INTERRUPT_P(TYPE) \
 ((TYPE) == M32R_FUNCTION_INTERRUPT)
-/* Compute the type of a function from its DECL.  */
-enum m32r_function_type m32r_compute_function_type ();
+
+/* Define this if you have defined special-purpose predicates in the
+   file `MACHINE.c'.  This macro is called within an initializer of an
+   array of structures.  The first field in the structure is the name
+   of a predicate and the second field is an array of rtl codes.  For
+   each predicate, list all rtl codes that can be in expressions
+   matched by the predicate.  The list should have a trailing comma.  */
+
+#define PREDICATE_CODES                                                        \
+{ "conditional_move_operand",  { REG, SUBREG, CONST_INT }},            \
+{ "carry_compare_operand",     { EQ, NE }},                            \
+{ "eqne_comparison_operator",  { EQ, NE }},                            \
+{ "signed_comparison_operator", { EQ, NE, LT, LE, GT, GE }},           \
+{ "move_dest_operand",         { REG, SUBREG, MEM }},                  \
+{ "move_src_operand",          { REG, SUBREG, MEM, CONST_INT,          \
+                                 CONST_DOUBLE, LABEL_REF, CONST,       \
+                                 SYMBOL_REF }},                        \
+{ "move_double_src_operand",   { REG, SUBREG, MEM, CONST_INT,          \
+                                 CONST_DOUBLE }},                      \
+{ "two_insn_const_operand",    { CONST_INT }},                         \
+{ "symbolic_operand",          { SYMBOL_REF, LABEL_REF, CONST }},      \
+{ "reg_or_int16_operand",      { REG, SUBREG, CONST_INT }},            \
+{ "reg_or_uint16_operand",     { REG, SUBREG, CONST_INT }},            \
+{ "reg_or_cmp_int16_operand",  { REG, SUBREG, CONST_INT }},            \
+{ "reg_or_zero_operand",       { REG, SUBREG, CONST_INT }},            \
+{ "cmp_int16_operand",         { CONST_INT }},                         \
+{ "call_address_operand",      { SYMBOL_REF, LABEL_REF, CONST }},      \
+{ "small_insn_p",              { INSN, CALL_INSN, JUMP_INSN }},        \
+{ "large_insn_p",              { INSN, CALL_INSN, JUMP_INSN }},
+
+/* Functions declared in m32r.c */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#ifdef BUFSIZE         /* stdio.h has been included, ok to use FILE * */
+#define STDIO_PROTO(ARGS) PROTO(ARGS)
+#else
+#define STDIO_PROTO(ARGS) ()
+#endif
+
+#ifndef TREE_CODE
+union tree_node;
+#define Tree union tree_node *
+#else
+#define Tree tree
+#endif
+
+#ifndef RTX_CODE
+struct rtx_def;
+#define Rtx struct rtx_def *
+#else
+#define Rtx rtx
+#endif
+
+extern void sbss_section                       PROTO((void));
+extern void sdata_section                      PROTO((void));
+extern void m32r_init                          PROTO((void));
+extern int  m32r_valid_machine_decl_attribute  PROTO((Tree, Tree, Tree, Tree));
+extern int  m32r_comp_type_attributes          PROTO((Tree, Tree));
+extern void m32r_select_section                        PROTO((Tree, int));
+extern void m32r_encode_section_info           PROTO((Tree));
+extern void m32r_init_expanders                        PROTO((void));
+extern int  call_address_operand               PROTO((Rtx, int));
+extern int  call_operand                       PROTO((Rtx, int));
+extern int  symbolic_operand                   PROTO((Rtx, int));
+extern int  small_data_operand                 PROTO((Rtx, int));
+extern int  addr24_operand                     PROTO((Rtx, int));
+extern int  addr32_operand                     PROTO((Rtx, int));
+extern int  call26_operand                     PROTO((Rtx, int));
+extern int  seth_add3_operand                  PROTO((Rtx, int));
+extern int  cmp_int16_operand                  PROTO((Rtx, int));
+extern int  uint16_operand                     PROTO((Rtx, int));
+extern int  reg_or_int16_operand               PROTO((Rtx, int));
+extern int  reg_or_uint16_operand              PROTO((Rtx, int));
+extern int  reg_or_cmp_nt16_operand            PROTO((Rtx, int));
+extern int  two_insn_const_operand             PROTO((Rtx, int));
+extern int  move_src_operand                   PROTO((Rtx, int));
+extern int  move_double_src_operand            PROTO((Rtx, int));
+extern int  move_dest_operand                  PROTO((Rtx, int));
+extern int  easy_di_const                      PROTO((Rtx));
+extern int  easy_df_const                      PROTO((Rtx));
+extern int  eqne_comparison_operator           PROTO((Rtx, int));
+extern int  signed_comparison_operator         PROTO((Rtx, int));
+extern int  memreg_operand                     PROTO((Rtx, int));
+extern int  small_insn_p                       PROTO((Rtx, int));
+extern int  large_insn_p                       PROTO((Rtx, int));
+extern int  m32r_select_cc_mode                        PROTO((int, Rtx, Rtx));
+extern Rtx  gen_compare                                PROTO((int, Rtx, Rtx, int));
+extern int  function_arg_partial_nregs         PROTO((CUMULATIVE_ARGS *,
+                                                      int, Tree, int));
+extern void m32r_setup_incoming_varargs                PROTO((CUMULATIVE_ARGS *,
+                                                      int, Tree, int *,
+                                                      int));
+extern int  m32r_address_code                  PROTO((Rtx));
+extern enum m32r_function_type m32r_compute_function_type
+                                               PROTO((Tree));
+extern unsigned m32r_compute_frame_size                PROTO((int));
+extern int  m32r_first_insn_address            PROTO((void));
+extern void m32r_output_function_prologue      STDIO_PROTO((FILE *, int));
+extern void m32r_output_function_epilogue      STDIO_PROTO((FILE *, int));
+extern void m32r_finalize_pic                  PROTO((void));
+extern void m32r_initialize_trampoline         PROTO((Rtx, Rtx, Rtx));
+extern void m32r_asm_file_start                        STDIO_PROTO((FILE *));
+extern void m32r_print_operand                 STDIO_PROTO((FILE *, Rtx, int));
+extern void m32r_print_operand_address         STDIO_PROTO((FILE *, Rtx));
+extern int  zero_and_one                       PROTO((Rtx, Rtx));
+extern int  conditional_move_operand           PROTO((Rtx, int));
+extern int  carry_compare_operand              PROTO((Rtx, int));
+extern char *emit_cond_move                    PROTO((Rtx *, Rtx));
+
+/* Needed by a peephole optimisation.  */
+#define PRESERVE_DEATH_INFO_REGNO_P(regno) (regno < FIRST_PSEUDO_REGISTER)
index 314f3ae..49f71d6 100644 (file)
@@ -1,5 +1,5 @@
 ;; Machine description of the Mitsubishi M32R cpu for GNU C compiler
-;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
 
 ;; This file is part of GNU CC.
 
 (define_asm_attributes
   [(set_attr "length" "4")
    (set_attr "type" "multi")])
+
+
+;; Whether an instruction is 16-bit or 32-bit
+(define_attr "insn_size" "short,long"
+  (if_then_else (eq_attr "length" "2")
+               (const_string "short")
+               (const_string "long")))
+
+(define_attr "m32r" "no,yes"
+  (const (symbol_ref "(TARGET_M32R != 0)")))
+
+
+
 \f
+;; ::::::::::::::::::::
+;; ::
+;; :: Function Units
+;; ::
+;; ::::::::::::::::::::
+
+;; On most RISC machines, there are instructions whose results are not
+;; available for a specific number of cycles.  Common cases are instructions
+;; that load data from memory.  On many machines, a pipeline stall will result
+;; if the data is referenced too soon after the load instruction.
+
+;; In addition, many newer microprocessors have multiple function units,
+;; usually one for integer and one for floating point, and often will incur
+;; pipeline stalls when a result that is needed is not yet ready.
+
+;; The descriptions in this section allow the specification of how much time
+;; must elapse between the execution of an instruction and the time when its
+;; result is used.  It also allows specification of when the execution of an
+;; instruction will delay execution of similar instructions due to function
+;; unit conflicts.
+
+;; For the purposes of the specifications in this section, a machine is divided
+;; into "function units", each of which execute a specific class of
+;; instructions in first-in-first-out order.  Function units that accept one
+;; instruction each cycle and allow a result to be used in the succeeding
+;; instruction (usually via forwarding) need not be specified.  Classic RISC
+;; microprocessors will normally have a single function unit, which we can call
+;; `memory'.  The newer "superscalar" processors will often have function units
+;; for floating point operations, usually at least a floating point adder and
+;; multiplier.
+
+;; Each usage of a function units by a class of insns is specified with a
+;; `define_function_unit' expression, which looks like this:
+
+;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY
+;;   ISSUE-DELAY [CONFLICT-LIST])
+
+;; NAME is a string giving the name of the function unit.
+
+;; MULTIPLICITY is an integer specifying the number of identical units in the
+;; processor.  If more than one unit is specified, they will be scheduled
+;; independently.  Only truly independent units should be counted; a pipelined
+;; unit should be specified as a single unit.  (The only common example of a
+;; machine that has multiple function units for a single instruction class that
+;; are truly independent and not pipelined are the two multiply and two
+;; increment units of the CDC 6600.)
+
+;; SIMULTANEITY specifies the maximum number of insns that can be executing in
+;; each instance of the function unit simultaneously or zero if the unit is
+;; pipelined and has no limit.
+
+;; All `define_function_unit' definitions referring to function unit NAME must
+;; have the same name and values for MULTIPLICITY and SIMULTANEITY.
+
+;; TEST is an attribute test that selects the insns we are describing in this
+;; definition.  Note that an insn may use more than one function unit and a
+;; function unit may be specified in more than one `define_function_unit'.
+
+;; READY-DELAY is an integer that specifies the number of cycles after which
+;; the result of the instruction can be used without introducing any stalls.
+
+;; ISSUE-DELAY is an integer that specifies the number of cycles after the
+;; instruction matching the TEST expression begins using this unit until a
+;; subsequent instruction can begin.  A cost of N indicates an N-1 cycle delay.
+;; A subsequent instruction may also be delayed if an earlier instruction has a
+;; longer READY-DELAY value.  This blocking effect is computed using the
+;; SIMULTANEITY, READY-DELAY, ISSUE-DELAY, and CONFLICT-LIST terms.  For a
+;; normal non-pipelined function unit, SIMULTANEITY is one, the unit is taken
+;; to block for the READY-DELAY cycles of the executing insn, and smaller
+;; values of ISSUE-DELAY are ignored.
+
+;; CONFLICT-LIST is an optional list giving detailed conflict costs for this
+;; unit.  If specified, it is a list of condition test expressions to be
+;; applied to insns chosen to execute in NAME following the particular insn
+;; matching TEST that is already executing in NAME.  For each insn in the list,
+;; ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost
+;; is zero.  If not specified, CONFLICT-LIST defaults to all instructions that
+;; use the function unit.
+
+;; Typical uses of this vector are where a floating point function unit can
+;; pipeline either single- or double-precision operations, but not both, or
+;; where a memory unit can pipeline loads, but not stores, etc.
+
+;; As an example, consider a classic RISC machine where the result of a load
+;; instruction is not available for two cycles (a single "delay" instruction is
+;; required) and where only one load instruction can be executed
+;; simultaneously.  This would be specified as:
+
+;; (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
+
+;; For the case of a floating point function unit that can pipeline
+;; either single or double precision, but not both, the following could be
+;; specified:
+;;
+;; (define_function_unit "fp" 1 0
+;;   (eq_attr "type" "sp_fp") 4 4
+;;   [(eq_attr "type" "dp_fp")])
+;;
+;; (define_function_unit "fp" 1 0
+;;   (eq_attr "type" "dp_fp") 4 4
+;;   [(eq_attr "type" "sp_fp")])
+
+;; Note: The scheduler attempts to avoid function unit conflicts and uses all
+;; the specifications in the `define_function_unit' expression.  It has
+;; recently come to our attention that these specifications may not allow
+;; modeling of some of the newer "superscalar" processors that have insns using
+;; multiple pipelined units.  These insns will cause a potential conflict for
+;; the second unit used during their execution and there is no way of
+;; representing that conflict.  We welcome any examples of how function unit
+;; conflicts work in such processors and suggestions for their representation.
+
 ;; Function units of the M32R
 ;; Units that take one cycle do not need to be specified.
 
-;; (define_function_unit {name} {num-units} {n-users} {test}
+;; (define_function_unit {name} {multiplicity} {simulataneity} {test}
 ;;                       {ready-delay} {issue-delay} [{conflict-list}])
 
 ;; References to loaded registers should wait a cycle.
   (not (eq_attr "length" "2"))
   1 0
   [(eq_attr "length" "2")])
+
 \f
 ;; Expand prologue as RTL
 ;; ??? Unfinished.
   DONE;
 }")
 
+
 ;; The cmp_xxx_insn patterns set the condition bit to the result of the
 ;; comparison.  There isn't a "compare equal" instruction so cmp_eqsi_insn
 ;; is quite inefficient.  However, it is rarely used.
        (eq:CC (match_operand:SI 0 "register_operand" "r,r")
               (match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P")))
    (clobber (match_scratch:SI 2 "=&r,&r"))]
-  "TARGET_OLD_COMPARE"
-  "@
-   mv %2,%0\;sub %2,%1\;cmpui %2,#1
-   add3 %2,%0,%#%N1\;cmpui %2,#1"
+  ""
+  "*
+{
+  if (which_alternative == 0)
+    {
+         return \"mv %2,%0\;sub %2,%1\;cmpui %2,#1\";
+    }
+  else
+    {
+        if (INTVAL (operands [1]) == 0)
+          return \"cmpui %0, #1\";
+        else if (REGNO (operands [2]) == REGNO (operands [0]))
+          return \"addi %0,%#%N1\;cmpui %2,#1\";
+        else
+          return \"add3 %2,%0,%#%N1\;cmpui %2,#1\";
+    }
+}"
   [(set_attr "type" "compare,compare")
    (set_attr "length" "8,8")])
 
   "@
    cmp %0,%1
    cmpi %0,%#%1"
-  [(set_attr "type" "compare")])
+  [(set_attr "type" "compare,compare")
+   (set_attr "length" "4,6")])
 
 (define_insn "cmp_ltusi_insn"
   [(set (reg:CC 17)
        (ltu:CC (match_operand:SI 0 "register_operand" "r,r")
                (match_operand:SI 1 "reg_or_uint16_operand" "r,K")))]
   ""
-  "@
-   cmpu %0,%1
-   cmpui %0,%#%1"
-  [(set_attr "type" "compare")])
+  "*
+{
+  if (which_alternative == 0)
+    return \"cmpu %0,%1\";
+  else
+   return \"cmpui %0,%#%1\";
+}"
+  [(set_attr "type" "compare")
+   (set_attr "length" "4,6")])
 
 ;; reg == small constant comparisons are best handled by putting the result
 ;; of the comparison in a tmp reg and then using beqz/bnez.
 ;; it contains 0/non-zero.
 
 (define_insn "cmp_ne_small_const_insn"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (ne:SI (match_operand:SI 1 "register_operand" "r")
-              (match_operand:SI 2 "cmp_int16_operand" "P")))]
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ne:SI (match_operand:SI 1 "register_operand" "0,r")
+              (match_operand:SI 2 "cmp_int16_operand" "S,P")))]
   ""
-  "add3 %0,%1,%#%N2"
+  "@
+   addi %0,%#%N2
+   add3 %0,%1,%#%N2"
   [(set_attr "type" "compare")
-   (set_attr "length" "4")])
+   (set_attr "length" "2,4")])
 \f
 ;; These control RTL generation for conditional jump insns.
 
   ""
   "
 {
-  operands[1] = gen_compare (EQ, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)EQ, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bne"
   ""
   "
 {
-  operands[1] = gen_compare (NE, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)NE, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bgt"
   ""
   "
 {
-  operands[1] = gen_compare (GT, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)GT, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "ble"
   ""
   "
 {
-  operands[1] = gen_compare (LE, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)LE, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bge"
   ""
   "
 {
-  operands[1] = gen_compare (GE, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)GE, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "blt"
   ""
   "
 {
-  operands[1] = gen_compare (LT, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)LT, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bgtu"
   ""
   "
 {
-  operands[1] = gen_compare (GTU, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)GTU, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bleu"
   ""
   "
 {
-  operands[1] = gen_compare (LEU, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)LEU, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bgeu"
   ""
   "
 {
-  operands[1] = gen_compare (GEU, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)GEU, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 (define_expand "bltu"
   ""
   "
 {
-  operands[1] = gen_compare (LTU, m32r_compare_op0, m32r_compare_op1);
+  operands[1] = gen_compare ((int)LTU, m32r_compare_op0, m32r_compare_op1, FALSE);
 }")
 
 ;; Now match both normal and inverted jump.
   ""
   "*
 {
-  if (GET_CODE (operands[1]) == NE)
-    return \"bc %l0\";
-  else
-    return \"bnc %l0\";
+  static char instruction[40];
+  sprintf (instruction, \"%s%s %%l0\",
+          (GET_CODE (operands[1]) == NE) ? \"bc\" : \"bnc\",
+          (get_attr_length (insn) == 2) ? \".s\" : \"\");
+  return instruction;
 }"
   [(set_attr "type" "branch")
    ; We use 400/800 instead of 512,1024 to account for inaccurate insn
   ""
   "*
 {
-  if (GET_CODE (operands[1]) == EQ)
-    return \"bc %l0\";
-  else
-    return \"bnc %l0\";
+  static char instruction[40];
+  sprintf (instruction, \"%s%s %%l0\",
+          (GET_CODE (operands[1]) == EQ) ? \"bc\" : \"bnc\",
+          (get_attr_length (insn) == 2) ? \".s\" : \"\");
+  return instruction;
 }"
   [(set_attr "type" "branch")
    ; We use 400/800 instead of 512,1024 to account for inaccurate insn
   "* return \"nop ; flush-icache\";"
   [(set_attr "type" "misc")])
 \f
+;; Conditional move instructions
+;; Based on those done for the d10v
+
+
+(define_expand "movsicc"
+  [
+   (set (match_operand:SI 0 "register_operand" "r")
+       (if_then_else:SI (match_operand 1 "" "")
+                        (match_operand:SI 2 "conditional_move_operand" "O")
+                        (match_operand:SI 3 "conditional_move_operand" "O")
+        )
+   )
+  ]
+  ""
+  "
+{
+  if (! zero_and_one (operands [2], operands [3]))
+    FAIL;
+
+  /* Generate the comparision that will set the carry flag.  */
+  operands[1] = gen_compare ((int)GET_CODE (operands[1]), m32r_compare_op0,
+                            m32r_compare_op1, TRUE);
+
+  /* See other movsicc pattern below for reason why.  */
+  emit_insn (gen_blockage());
+}")
+
+;; Generate the conditional instructions based on how the carry flag is examined.
+(define_insn "*movsicc_internal"
+  [(set (match_operand:SI 0 "register_operand" "r")
+       (if_then_else:SI (match_operand 1 "carry_compare_operand" "")
+                        (match_operand:SI 2 "conditional_move_operand" "O")
+                        (match_operand:SI 3 "conditional_move_operand" "O")
+        )
+   )]
+  "zero_and_one (operands [2], operands[3])"
+  "* return emit_cond_move (operands, insn);"
+  [(set_attr "type"   "move")
+   (set_attr "length" "8")
+  ]
+)
+
+
+
+\f
 ;; Split up troublesome insns for better scheduling.
 \f
 ;; Peepholes go at the end.
   "st %1,@+%0"
   [(set_attr "type" "store")
    (set_attr "length" "2")])
+
+;; This case is triggered by compiling this code:
+;; 
+;; extern void sub(int *);
+;; void main (void)
+;; {
+;;   int i=2,j=3,k;
+;;   while (i < j)  sub(&k);
+;;   i = j / k;
+;;   sub(&i);
+;;   i = j - k;
+;;   sub(&i);
+;; }
+;;
+;; Without the peephole the following assembler is generated for the
+;; divide and subtract expressions:
+;;
+;;         div r5,r4     
+;;         mv r4,r5      
+;;         st r4,@(4,sp) 
+;;         bl sub
+;; 
+;; Simialr code is produced for the subtract expression.  With this
+;; peephole the redundant move is eliminated.
+;;
+;; This optimisation onbly works if PRESERVE_DEATH_INFO_REGNO_P is
+;; defined in m32r.h
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "r")
+        (match_operand:SI 1 "register_operand" "r")
+   )
+   (set (mem:SI (plus: SI (match_operand:SI 2 "register_operand" "r")
+                (match_operand:SI 3 "immediate_operand" "J")))
+        (match_dup 0)
+   )
+  ]
+  "dead_or_set_p (insn, operands [0])"
+  "st %1,@(%3,%2)"
+  [(set_attr "type" "store")
+   (set_attr "length" "4")
+  ]
+)
index 6005eb9..3d8da58 100644 (file)
@@ -39,6 +39,7 @@ crtfini.o: $(srcdir)/config/m32r/initfini.c $(GCC_PASSES) $(CONFIG_H)
          -DCRT_FINI -finhibit-size-directive -fno-inline-functions \
          -g0 -c $(srcdir)/config/m32r/initfini.c -o crtfini.o
 
+
 # -mmodel={small,medium} requires separate libraries.
 # We don't build libraries for the large model, instead we use the medium
 # libraries.  The only difference is that the large model can handle jumps
@@ -48,6 +49,7 @@ MULTILIB_OPTIONS = mmodel=small/mmodel=medium
 MULTILIB_DIRNAMES = small medium
 MULTILIB_MATCHES = mmodel?medium=mmodel?large
 
+
 # Set MULTILIB_EXTRA_OPTS so shipped libraries have small data in .sdata and
 # SHN_M32R_SCOMMON.
 # This is important for objects referenced in system header files.
index 3f2f16c..7a4c917 100755 (executable)
@@ -4580,7 +4580,7 @@ fi
 if [ x$enable_haifa = x ]
 then
   case $target in
-    alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*)
+    alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
       enable_haifa=yes;;
   esac
 fi
index 6e6e34a..67b7fbd 100644 (file)
@@ -2891,7 +2891,7 @@ fi
 if [[ x$enable_haifa = x ]]
 then
   case $target in
-    alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-*)
+    alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc-* | m32r*-*)
       enable_haifa=yes;;
   esac
 fi