aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/m32r/m32r.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/m32r/m32r.c')
-rw-r--r--gcc/config/m32r/m32r.c503
1 files changed, 405 insertions, 98 deletions
diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c
index 4b23157..f547332 100644
--- a/gcc/config/m32r/m32r.c
+++ b/gcc/config/m32r/m32r.c
@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */
#include "function.h"
#include "recog.h"
#include "toplev.h"
+#include "m32r-protos.h"
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
@@ -44,16 +45,18 @@ rtx m32r_compare_op0, m32r_compare_op1;
char m32r_punct_chars[256];
/* Selected code model. */
-char *m32r_model_string = M32R_MODEL_DEFAULT;
+const char * m32r_model_string = M32R_MODEL_DEFAULT;
enum m32r_model m32r_model;
/* Selected SDA support. */
-char *m32r_sdata_string = M32R_SDATA_DEFAULT;
+const char * m32r_sdata_string = M32R_SDATA_DEFAULT;
enum m32r_sdata m32r_sdata;
+/* Scheduler support */
+int m32r_sched_odd_word_p;
/* Forward declaration. */
-static void init_reg_tables PROTO((void));
+static void init_reg_tables PROTO ((void));
/* Called by OVERRIDE_OPTIONS to initialize various things. */
@@ -88,7 +91,6 @@ 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
@@ -104,7 +106,7 @@ enum m32r_mode_class
{
C_MODE,
S_MODE, D_MODE, T_MODE, O_MODE,
- SF_MODE, DF_MODE, TF_MODE, OF_MODE
+ SF_MODE, DF_MODE, TF_MODE, OF_MODE, A_MODE
};
/* Modes for condition codes. */
@@ -119,6 +121,8 @@ enum m32r_mode_class
/* Modes for quad-word and smaller quantities. */
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
+/* Modes for accumulators. */
+#define A_MODES (1 << (int) A_MODE)
/* Value is 1 if register/mode pair is acceptable on arc. */
@@ -126,7 +130,7 @@ 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
+ S_MODES, C_MODES, A_MODES
};
unsigned int m32r_mode_class [NUM_MACHINE_MODES];
@@ -451,23 +455,21 @@ m32r_init_expanders ()
/* Acceptable arguments to the call insn. */
int
-call_address_operand (op, int_mode)
+call_address_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- return symbolic_operand (op, int_mode);
+ return symbolic_operand (op, mode);
/* Constants and values in registers are not OK, because
the m32r BL instruction can only support PC relative branching. */
}
int
-call_operand (op, int_mode)
+call_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
-
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
@@ -477,9 +479,9 @@ call_operand (op, int_mode)
/* Returns 1 if OP is a symbol reference. */
int
-symbolic_operand (op, int_mode)
+symbolic_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
@@ -496,9 +498,9 @@ symbolic_operand (op, int_mode)
/* Return 1 if OP is a reference to an object in .sdata/.sbss. */
int
-small_data_operand (op, int_mode)
+small_data_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (! TARGET_SDATA_USE)
return 0;
@@ -519,9 +521,9 @@ small_data_operand (op, int_mode)
/* Return 1 if OP is a symbol that can use 24 bit addressing. */
int
-addr24_operand (op, int_mode)
+addr24_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR24;
@@ -551,24 +553,24 @@ addr24_operand (op, int_mode)
/* Return 1 if OP is a symbol that needs 32 bit addressing. */
int
-addr32_operand (op, int_mode)
+addr32_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
if (GET_CODE (op) == LABEL_REF)
return TARGET_ADDR32;
if (GET_CODE (op) == SYMBOL_REF)
- return (! addr24_operand (op, int_mode)
- && ! small_data_operand (op, int_mode));
+ return (! addr24_operand (op, mode)
+ && ! small_data_operand (op, 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, int_mode)
- && ! small_data_operand (op, int_mode));
+ return (! addr24_operand (op, mode)
+ && ! small_data_operand (op, mode));
}
return 0;
@@ -577,9 +579,9 @@ addr32_operand (op, int_mode)
/* Return 1 if OP is a function that can be called with the `bl' insn. */
int
-call26_operand (op, int_mode)
+call26_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SYMBOL_REF)
return ! LARGE_NAME_P (XSTR (op, 0));
@@ -590,9 +592,9 @@ call26_operand (op, int_mode)
/* Returns 1 if OP is an acceptable operand for seth/add3. */
int
-seth_add3_operand (op, int_mode)
+seth_add3_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SYMBOL_REF
|| GET_CODE (op) == LABEL_REF)
@@ -608,13 +610,25 @@ seth_add3_operand (op, int_mode)
return 0;
}
+/* Return true if OP is a signed 8 bit immediate value. */
+
+int
+int8_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+ return INT8_P (INTVAL (op));
+}
+
/* Return true if OP is a signed 16 bit immediate value
useful in comparisons. */
int
-cmp_int16_operand (op, int_mode)
+cmp_int16_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT)
return 0;
@@ -624,24 +638,22 @@ cmp_int16_operand (op, int_mode)
/* Return true if OP is an unsigned 16 bit immediate value. */
int
-uint16_operand (op, int_mode)
+uint16_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT)
return 0;
return UINT16_P (INTVAL (op));
}
-/* Return true if OP is a register or signed 8 bit value. */
+/* Return true if OP is a register or signed 16 bit value. */
int
-reg_or_int16_operand (op, int_mode)
+reg_or_int16_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode 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)
@@ -652,12 +664,10 @@ reg_or_int16_operand (op, int_mode)
/* Return true if OP is a register or an unsigned 16 bit value. */
int
-reg_or_uint16_operand (op, int_mode)
+reg_or_uint16_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode 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)
@@ -665,17 +675,37 @@ reg_or_uint16_operand (op, int_mode)
return UINT16_P (INTVAL (op));
}
-/* Return true if OP is a register or signed 16 bit value for compares. */
+/* Return true if OP is a register or an integer value that can be
+ used is SEQ/SNE. We can use either XOR of the value or ADD of
+ the negative of the value for the constant. Don't allow 0,
+ because that is special cased. */
int
-reg_or_cmp_int16_operand (op, int_mode)
+reg_or_eq_int16_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
+ HOST_WIDE_INT value;
if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
return register_operand (op, mode);
+
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+
+ value = INTVAL (op);
+ return (value != 0) && (UINT16_P (value) || CMP_INT16_P (-value));
+}
+
+/* Return true if OP is a register or signed 16 bit value for compares. */
+
+int
+reg_or_cmp_int16_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
+ return register_operand (op, mode);
if (GET_CODE (op) != CONST_INT)
return 0;
return CMP_INT16_P (INTVAL (op));
@@ -684,9 +714,9 @@ reg_or_cmp_int16_operand (op, int_mode)
/* Return true if OP is a const_int requiring two instructions to load. */
int
-two_insn_const_operand (op, int_mode)
+two_insn_const_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT)
return 0;
@@ -701,16 +731,15 @@ two_insn_const_operand (op, int_mode)
move source. */
int
-move_src_operand (op, int_mode)
+move_src_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case SYMBOL_REF :
case CONST :
- return addr24_operand (op, int_mode);
+ return addr24_operand (op, 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
@@ -743,6 +772,9 @@ move_src_operand (op, int_mode)
else
return register_operand (op, mode);
case MEM :
+ if (GET_CODE (XEXP (op, 0)) == PRE_INC
+ || GET_CODE (XEXP (op, 0)) == PRE_DEC)
+ return 0; /* loads can't do pre-{inc,dec} */
return address_operand (XEXP (op, 0), mode);
default :
return 0;
@@ -753,11 +785,10 @@ move_src_operand (op, int_mode)
move source. */
int
-move_double_src_operand (op, int_mode)
+move_double_src_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case CONST_INT :
@@ -769,7 +800,7 @@ move_double_src_operand (op, int_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), int_mode);
+ return move_double_src_operand (SUBREG_REG (op), mode);
else
return register_operand (op, mode);
case MEM :
@@ -786,11 +817,10 @@ move_double_src_operand (op, int_mode)
/* Return true if OP is an acceptable argument for a move destination. */
int
-move_dest_operand (op, int_mode)
+move_dest_operand (op, mode)
rtx op;
- int int_mode;
+ enum machine_mode mode;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
switch (GET_CODE (op))
{
case REG :
@@ -803,6 +833,8 @@ move_dest_operand (op, int_mode)
else
return register_operand (op, mode);
case MEM :
+ if (GET_CODE (XEXP (op, 0)) == POST_INC)
+ return 0; /* stores can't do post inc */
return address_operand (XEXP (op, 0), mode);
default :
return 0;
@@ -853,9 +885,9 @@ easy_df_const (op)
/* Return 1 if OP is an EQ or NE comparison operator. */
int
-eqne_comparison_operator (op, int_mode)
+eqne_comparison_operator (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
@@ -867,9 +899,9 @@ eqne_comparison_operator (op, int_mode)
/* Return 1 if OP is a signed comparison operator. */
int
-signed_comparison_operator (op, int_mode)
+signed_comparison_operator (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
@@ -883,20 +915,48 @@ signed_comparison_operator (op, int_mode)
This is used in insn length calcs. */
int
-memreg_operand (op, int_mode)
+memreg_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG;
}
+/* Return true if OP is an acceptable input argument for a zero/sign extend
+ operation. */
+
+int
+extend_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ rtx addr;
+
+ switch (GET_CODE (op))
+ {
+ case REG :
+ case SUBREG :
+ return register_operand (op, mode);
+
+ case MEM :
+ addr = XEXP (op, 0);
+ if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
+ return 0; /* loads can't do pre inc/pre dec */
+
+ return address_operand (addr, mode);
+
+ default :
+ return 0;
+ }
+}
+
/* 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)
+small_insn_p (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
return 1;
@@ -910,9 +970,9 @@ small_insn_p (op, int_mode)
/* Return non-zero if the operand is an insn that is a large insn. */
int
-large_insn_p (op, int_mode)
+large_insn_p (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_RTX_CLASS (GET_CODE (op)) != 'i')
return 0;
@@ -932,13 +992,13 @@ m32r_select_cc_mode (op, x, y)
rtx x ATTRIBUTE_UNUSED;
rtx y ATTRIBUTE_UNUSED;
{
- return (int)SImode;
+ 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].
If need_compare is true then the comparison insn must be generated, rather
- than being susummed into the following branch instruction. */
+ than being susummed into the following branch instruction. */
rtx
gen_compare (code, x, y, need_compare)
@@ -965,7 +1025,7 @@ gen_compare (code, x, y, need_compare)
case GEU: compare_code = LTU; branch_code = EQ; break;
default:
- abort();
+ abort ();
}
if (need_compare)
@@ -992,7 +1052,7 @@ gen_compare (code, x, y, need_compare)
if (register_operand (y, SImode) /* reg equal to reg. */
|| y == const0_rtx) /* req equal to zero. */
{
- emit_insn (gen_cmp_eqsi_insn (x, y));
+ emit_insn (gen_cmp_eqsi_insn (x, y));
return gen_rtx (code, mode, cc_reg, const0_rtx);
}
@@ -1031,7 +1091,7 @@ gen_compare (code, x, y, need_compare)
code = NE;
break;
default:
- abort();
+ abort ();
}
return gen_rtx (code, mode, cc_reg, const0_rtx);
@@ -1083,7 +1143,6 @@ gen_compare (code, x, y, need_compare)
}
}
else
- if (! TARGET_OLD_COMPARE)
{
/* reg/reg equal comparison */
if (compare_code == EQ
@@ -1280,13 +1339,12 @@ gen_split_move_double (operands)
/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */
int
-function_arg_partial_nregs (cum, int_mode, type, named)
+function_arg_partial_nregs (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
- int int_mode;
+ enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
- enum machine_mode mode = (enum machine_mode)int_mode;
int ret;
int size = (((mode == BLKmode && type)
? int_size_in_bytes (type)
@@ -1310,14 +1368,13 @@ function_arg_partial_nregs (cum, int_mode, type, named)
and mode MODE, and we rely on this fact. */
void
-m32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl)
+m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
CUMULATIVE_ARGS *cum;
- int int_mode;
+ enum machine_mode 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)
@@ -1353,6 +1410,7 @@ m32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl)
}
}
+
/* Implement `va_arg'. */
rtx
@@ -1415,6 +1473,218 @@ m32r_va_arg (valist, type)
return addr_rtx;
}
+int
+m32r_adjust_cost (insn, link, dep_insn, cost)
+ rtx insn ATTRIBUTE_UNUSED;
+ rtx link ATTRIBUTE_UNUSED;
+ rtx dep_insn ATTRIBUTE_UNUSED;
+ int cost;
+{
+ return 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.
+
+ On the m32r, increase the priority of long instructions so that
+ the short instructions are scheduled ahead of the long ones. */
+
+int
+m32r_adjust_priority (insn, priority)
+ rtx insn;
+ int priority;
+{
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ enum rtx_code code = GET_CODE (PATTERN (insn));
+ if (code != USE && code != CLOBBER && code != ADDR_VEC
+ && get_attr_insn_size (insn) != INSN_SIZE_SHORT)
+ priority <<= 3;
+ }
+
+ return priority;
+}
+
+
+/* Initialize for scheduling a group of instructions. */
+
+void
+m32r_sched_init (stream, verbose)
+ FILE * stream ATTRIBUTE_UNUSED;
+ int verbose ATTRIBUTE_UNUSED;
+{
+ m32r_sched_odd_word_p = FALSE;
+}
+
+
+/* Reorder the schedulers priority list if needed */
+
+void
+m32r_sched_reorder (stream, verbose, ready, n_ready)
+ FILE * stream;
+ int verbose;
+ rtx * ready;
+ int n_ready;
+{
+ if (TARGET_DEBUG)
+ return;
+
+ if (verbose <= 7)
+ stream = (FILE *)0;
+
+ if (stream)
+ fprintf (stream,
+ ";;\t\t::: Looking at %d insn(s) on ready list, boundary is %s word\n",
+ n_ready,
+ (m32r_sched_odd_word_p) ? "odd" : "even");
+
+ if (n_ready > 1)
+ {
+ rtx * long_head = (rtx *) alloca (sizeof (rtx) * n_ready);
+ rtx * long_tail = long_head;
+ rtx * short_head = (rtx *) alloca (sizeof (rtx) * n_ready);
+ rtx * short_tail = short_head;
+ rtx * new_head = (rtx *) alloca (sizeof (rtx) * n_ready);
+ rtx * new_tail = new_head + (n_ready - 1);
+ int i;
+
+ /* Loop through the instructions, classifing them as short/long. Try
+ to keep 2 short together and/or 1 long. Note, the ready list is
+ actually ordered backwards, so keep it in that manner. */
+ for (i = n_ready-1; i >= 0; i--)
+ {
+ rtx insn = ready[i];
+ enum rtx_code code;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+ || (code = GET_CODE (PATTERN (insn))) == USE
+ || code == CLOBBER || code == ADDR_VEC)
+ {
+ /* Dump all current short/long insns just in case */
+ while (long_head != long_tail)
+ *new_tail-- = *long_head++;
+
+ while (short_head != short_tail)
+ *new_tail-- = *short_head++;
+
+ *new_tail-- = insn;
+ if (stream)
+ fprintf (stream,
+ ";;\t\t::: Skipping non instruction %d\n",
+ INSN_UID (insn));
+
+ }
+
+ else
+ {
+ if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
+ *long_tail++ = insn;
+
+ else
+ *short_tail++ = insn;
+ }
+ }
+
+ /* If we are on an odd word, emit a single short instruction if
+ we can */
+ if (m32r_sched_odd_word_p && short_head != short_tail)
+ *new_tail-- = *short_head++;
+
+ /* Now dump out all of the long instructions */
+ while (long_head != long_tail)
+ *new_tail-- = *long_head++;
+
+ /* Now dump out all of the short instructions */
+ while (short_head != short_tail)
+ *new_tail-- = *short_head++;
+
+ if (new_tail+1 != new_head)
+ abort ();
+
+ bcopy ((char *) new_head, (char *) ready, sizeof (rtx) * n_ready);
+ if (stream)
+ {
+#ifdef HAIFA
+ fprintf (stream, ";;\t\t::: New ready list: ");
+ debug_ready_list (ready, n_ready);
+#else
+ int i;
+ for (i = 0; i < n_ready; i++)
+ {
+ rtx insn = ready[i];
+ enum rtx_code code;
+
+ fprintf (stream, " %d", INSN_UID (ready[i]));
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
+ || (code = GET_CODE (PATTERN (insn))) == USE
+ || code == CLOBBER || code == ADDR_VEC)
+ fputs ("(?)", stream);
+
+ else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
+ fputs ("(l)", stream);
+
+ else
+ fputs ("(s)", stream);
+ }
+
+ fprintf (stream, "\n");
+#endif
+ }
+ }
+}
+
+
+/* If we have a machine that can issue a variable # of instructions
+ per cycle, indicate how many more instructions can be issued
+ after the current one. */
+int
+m32r_sched_variable_issue (stream, verbose, insn, how_many)
+ FILE * stream;
+ int verbose;
+ rtx insn;
+ int how_many;
+{
+ int orig_odd_word_p = m32r_sched_odd_word_p;
+ int short_p = FALSE;
+
+ how_many--;
+ if (how_many > 0 && !TARGET_DEBUG)
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ how_many++;
+
+ else if (GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER
+ || GET_CODE (PATTERN (insn)) == ADDR_VEC)
+ how_many++;
+
+ else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
+ {
+ how_many = 0;
+ m32r_sched_odd_word_p = 0;
+ }
+ else
+ {
+ m32r_sched_odd_word_p = !m32r_sched_odd_word_p;
+ short_p = TRUE;
+ }
+ }
+
+ if (verbose > 7 && stream)
+ fprintf (stream,
+ ";;\t\t::: %s insn %d starts on an %s word, can emit %d more instruction(s)\n",
+ short_p ? "short" : "long",
+ INSN_UID (insn),
+ orig_odd_word_p ? "odd" : "even",
+ how_many);
+
+ return how_many;
+}
+
/* Cost functions. */
/* Provide the costs of an addressing mode that contains ADDR.
@@ -1638,7 +1908,7 @@ m32r_expand_prologue ()
{
int regno;
int frame_size;
- unsigned int gmask = current_frame_info.gmask;
+ unsigned int gmask;
if (! current_frame_info.initialized)
m32r_compute_frame_size (get_frame_size ());
@@ -1849,6 +2119,22 @@ m32r_output_function_epilogue (file, size)
m32r_compute_function_type (NULL_TREE);
}
+/* Return non-zero if this function is known to have a null or 1 instruction
+ epilogue. */
+
+int
+direct_return ()
+{
+ if (!reload_completed)
+ return FALSE;
+
+ if (! current_frame_info.initialized)
+ m32r_compute_frame_size (get_frame_size ());
+
+ return current_frame_info.total_size == 0;
+}
+
+
/* PIC */
/* Emit special PIC prologues and epilogues. */
@@ -1968,7 +2254,7 @@ m32r_print_operand (file, x, code)
if (GET_CODE (x) != CONST_DOUBLE
|| GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
- abort ();
+ fatal_insn ("Bad insn for 'A'", x);
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
REAL_VALUE_TO_DECIMAL (d, "%.20e", str);
fprintf (file, "%s", str);
@@ -2088,21 +2374,21 @@ m32r_print_operand (file, x, code)
if (GET_CODE (addr) == PRE_INC)
{
if (GET_CODE (XEXP (addr, 0)) != REG)
- abort ();
+ fatal_insn ("Pre-increment address is not a register", x);
fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]);
}
else if (GET_CODE (addr) == PRE_DEC)
{
if (GET_CODE (XEXP (addr, 0)) != REG)
- abort ();
+ fatal_insn ("Pre-decrement address is not a register", x);
fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]);
}
else if (GET_CODE (addr) == POST_INC)
{
if (GET_CODE (XEXP (addr, 0)) != REG)
- abort ();
+ fatal_insn ("Post-increment address is not a register", x);
fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]);
}
@@ -2180,7 +2466,7 @@ m32r_print_operand_address (file, addr)
fputs (reg_names[REGNO (base)], file);
}
else
- abort ();
+ fatal_insn ("Bad address", addr);
}
else if (GET_CODE (base) == LO_SUM)
{
@@ -2196,12 +2482,12 @@ m32r_print_operand_address (file, addr)
fputs (reg_names[REGNO (XEXP (base, 0))], file);
}
else
- abort ();
+ fatal_insn ("Bad address", addr);
break;
case LO_SUM :
if (GET_CODE (XEXP (addr, 0)) != REG)
- abort ();
+ fatal_insn ("Lo_sum not of register", addr);
if (small_data_operand (XEXP (addr, 1), VOIDmode))
fputs ("sda(", file);
else
@@ -2244,12 +2530,10 @@ zero_and_one (operand1, operand2)
/* Return non-zero if the operand is suitable for use in a conditional move sequence. */
int
-conditional_move_operand (operand, int_mode)
+conditional_move_operand (operand, mode)
rtx operand;
- int int_mode;
+ enum machine_mode 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;
@@ -2276,13 +2560,13 @@ conditional_move_operand (operand, int_mode)
/* Return true if the code is a test of the carry bit */
int
-carry_compare_operand (op, int_mode)
+carry_compare_operand (op, mode)
rtx op;
- int int_mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx x;
- if (GET_MODE (op) != SImode && GET_MODE (op) != VOIDmode)
+ if (GET_MODE (op) != CCmode && GET_MODE (op) != VOIDmode)
return FALSE;
if (GET_CODE (op) != NE && GET_CODE (op) != EQ)
@@ -2299,7 +2583,6 @@ carry_compare_operand (op, int_mode)
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].
@@ -2341,6 +2624,30 @@ emit_cond_move (operands, insn)
return buffer;
}
+/* Returns true if the registers contained in the two
+ rtl expressions are different. */
+int
+m32r_not_same_reg (a, b)
+ rtx a;
+ rtx b;
+{
+ int reg_a = -1;
+ int reg_b = -2;
+
+ while (GET_CODE (a) == SUBREG)
+ a = SUBREG_REG (a);
+
+ if (GET_CODE (a) == REG)
+ reg_a = REGNO (a);
+
+ while (GET_CODE (b) == SUBREG)
+ b = SUBREG_REG (b);
+
+ if (GET_CODE (b) == REG)
+ reg_b = REGNO (b);
+
+ return reg_a != reg_b;
+}
/* Use a library function to move some bytes. */
@@ -2600,7 +2907,7 @@ m32r_output_block_move (insn, operands)
int
m32r_block_immediate_operand (op, mode)
rtx op;
- int mode ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT
|| INTVAL (op) > MAX_MOVE_BYTES