/* Subroutines for insn-output.c for Renesas H8/300.
- Copyright (C) 1992-2015 Free Software Foundation, Inc.
+ Copyright (C) 1992-2020 Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com),
Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#define IN_TARGET_CODE 1
+
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
-#include "tree.h"
+#include "target.h"
#include "rtl.h"
+#include "tree.h"
#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
+#include "diagnostic-core.h"
#include "alias.h"
#include "stor-layout.h"
#include "varasm.h"
#include "calls.h"
-#include "stringpool.h"
-#include "regs.h"
-#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
-#include "recog.h"
-#include "expmed.h"
-#include "dojump.h"
#include "explow.h"
-#include "emit-rtl.h"
-#include "stmt.h"
#include "expr.h"
-#include "insn-codes.h"
-#include "optabs.h"
-#include "diagnostic-core.h"
-#include "c-family/c-pragma.h" /* ??? */
-#include "tm_p.h"
#include "tm-constrs.h"
-#include "target.h"
-#include "cfgrtl.h"
-#include "cfganal.h"
-#include "lcm.h"
-#include "cfgbuild.h"
-#include "cfgcleanup.h"
#include "builtins.h"
/* This file should be included last. */
static tree h8300_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
static tree h8300_handle_eightbit_data_attribute (tree *, tree, tree, int, bool *);
static tree h8300_handle_tiny_data_attribute (tree *, tree, tree, int, bool *);
-static void h8300_print_operand_address (FILE *, rtx);
+static void h8300_print_operand_address (FILE *, machine_mode, rtx);
static void h8300_print_operand (FILE *, rtx, int);
static bool h8300_print_operand_punct_valid_p (unsigned char code);
#ifndef OBJECT_FORMAT_ELF
#ifndef OBJECT_FORMAT_ELF
if (TARGET_H8300SX)
{
- error ("-msx is not supported in coff");
+ error ("%<-msx%> is not supported in coff");
target_flags |= MASK_H8300S;
}
#endif
if (!TARGET_H8300S && TARGET_MAC)
{
- error ("-ms2600 is used without -ms");
+ error ("%<-ms2600%> is used without %<-ms%>");
target_flags |= MASK_H8300S_1;
}
if (TARGET_H8300 && TARGET_NORMAL_MODE)
{
- error ("-mn is used without -mh or -ms or -msx");
+ error ("%<-mn%> is used without %<-mh%> or %<-ms%> or %<-msx%>");
target_flags ^= MASK_NORMAL_MODE;
}
if (! TARGET_H8300S && TARGET_EXR)
{
- error ("-mexr is used without -ms");
+ error ("%<-mexr%> is used without %<-ms%>");
target_flags |= MASK_H8300S_1;
}
if (TARGET_H8300 && TARGET_INT32)
{
- error ("-mint32 is not supported for H8300 and H8300L targets");
+ error ("%<-mint32%> is not supported for H8300 and H8300L targets");
target_flags ^= MASK_INT32;
}
if ((!TARGET_H8300S && TARGET_EXR) && (!TARGET_H8300SX && TARGET_EXR))
{
- error ("-mexr is used without -ms or -msx");
+ error ("%<-mexr%> is used without %<-ms%> or %<-msx%>");
target_flags |= MASK_H8300S_1;
}
if ((!TARGET_H8300S && TARGET_NEXR) && (!TARGET_H8300SX && TARGET_NEXR))
{
- warning (OPT_mno_exr, "-mno-exr valid only with -ms or -msx \
- - Option ignored!");
+ warning (OPT_mno_exr, "%<-mno-exr%> valid only with %<-ms%> or "
+ "%<-msx%> - Option ignored!");
}
#ifdef H8300_LINUX
if ((TARGET_NORMAL_MODE))
{
- error ("-mn is not supported for linux targets");
+ error ("%<-mn%> is not supported for linux targets");
target_flags ^= MASK_NORMAL_MODE;
}
#endif
&& ! TREE_THIS_VOLATILE (current_function_decl) \
&& (h8300_saveall_function_p (current_function_decl) \
/* Save any call saved register that was used. */ \
- || (df_regs_ever_live_p (regno) && !call_used_regs[regno]) \
+ || (df_regs_ever_live_p (regno) \
+ && !call_used_or_fixed_reg_p (regno)) \
/* Save the frame pointer if it was used. */ \
|| (regno == HARD_FRAME_POINTER_REGNUM && df_regs_ever_live_p (regno)) \
/* Save any register used in an interrupt handler. */ \
/* Save call clobbered registers in non-leaf interrupt \
handlers. */ \
|| (h8300_current_function_interrupt_function_p () \
- && call_used_regs[regno] \
+ && call_used_or_fixed_reg_p (regno) \
&& !crtl->is_leaf)))
/* We use this to wrap all emitted insns in the prologue. */
if (TARGET_H8300S)
{
/* See how many registers we can push at the same time. */
- if ((!TARGET_H8300SX || (regno & 3) == 0)
+ if ((TARGET_H8300SX || (regno & 3) == 0)
&& ((saved_regs >> regno) & 0x0f) == 0x0f)
n_regs = 4;
- else if ((!TARGET_H8300SX || (regno & 3) == 0)
+ else if ((TARGET_H8300SX || (regno & 3) == 0)
&& ((saved_regs >> regno) & 0x07) == 0x07)
n_regs = 3;
- else if ((!TARGET_H8300SX || (regno & 1) == 0)
+ else if ((TARGET_H8300SX || (regno & 1) == 0)
&& ((saved_regs >> regno) & 0x03) == 0x03)
n_regs = 2;
}
switch (mode)
{
- case HImode:
+ case E_HImode:
gen_add = gen_addhi3;
break;
- case SImode:
+ case E_SImode:
gen_add = gen_addsi3;
break;
pragma_saveall = 1;
}
-/* If the next function argument with MODE and TYPE is to be passed in
- a register, return a reg RTX for the hard register in which to pass
- the argument. CUM represents the state after the last argument.
- If the argument is to be pushed, NULL_RTX is returned.
+/* If the next function argument ARG is to be passed in a register, return
+ a reg RTX for the hard register in which to pass the argument. CUM
+ represents the state after the last argument. If the argument is to
+ be pushed, NULL_RTX is returned.
On the H8/300 all normal args are pushed, unless -mquickcall in which
case the first 3 arguments are passed in registers. */
static rtx
-h8300_function_arg (cumulative_args_t cum_v, machine_mode mode,
- const_tree type, bool named)
+h8300_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int regpass = 0;
/* Never pass unnamed arguments in registers. */
- if (!named)
+ if (!arg.named)
return NULL_RTX;
/* Pass 3 regs worth of data in regs when user asked on the command line. */
if (regpass)
{
- int size;
-
- if (mode == BLKmode)
- size = int_size_in_bytes (type);
- else
- size = GET_MODE_SIZE (mode);
-
+ int size = arg.promoted_size_in_bytes ();
if (size + cum->nbytes <= regpass * UNITS_PER_WORD
&& cum->nbytes / UNITS_PER_WORD <= 3)
- result = gen_rtx_REG (mode, cum->nbytes / UNITS_PER_WORD);
+ result = gen_rtx_REG (arg.mode, cum->nbytes / UNITS_PER_WORD);
}
return result;
}
-/* Update the data in CUM to advance over an argument
- of mode MODE and data type TYPE.
- (TYPE is null for libcalls where that information may not be available.) */
+/* Update the data in CUM to advance over argument ARG. */
static void
-h8300_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
- const_tree type, bool named ATTRIBUTE_UNUSED)
+h8300_function_arg_advance (cumulative_args_t cum_v,
+ const function_arg_info &arg)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
- cum->nbytes += (mode != BLKmode
- ? (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) & -UNITS_PER_WORD
- : (int_size_in_bytes (type) + UNITS_PER_WORD - 1) & -UNITS_PER_WORD);
+ cum->nbytes += ((arg.promoted_size_in_bytes () + UNITS_PER_WORD - 1)
+ & -UNITS_PER_WORD);
}
\f
*total = 0;
return true;
}
- if (-4 <= n && n <= 4)
+ if (n >= -4 && n <= 4)
{
switch ((int) n)
{
if (TARGET_H8300SX)
switch (GET_MODE (x))
{
- case QImode:
- case HImode:
+ case E_QImode:
+ case E_HImode:
*total = COSTS_N_INSNS (!speed ? 4 : 10);
return false;
- case SImode:
+ case E_SImode:
*total = COSTS_N_INSNS (!speed ? 4 : 18);
return false;
if (TARGET_H8300SX)
switch (GET_MODE (x))
{
- case QImode:
- case HImode:
+ case E_QImode:
+ case E_HImode:
*total = COSTS_N_INSNS (2);
return false;
- case SImode:
+ case E_SImode:
*total = COSTS_N_INSNS (5);
return false;
case CONST_DOUBLE:
{
long val;
- REAL_VALUE_TYPE rv;
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val);
fprintf (file, "#%ld", ((val >> 16) & 0xffff));
break;
}
case CONST_DOUBLE:
{
long val;
- REAL_VALUE_TYPE rv;
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val);
fprintf (file, "#%ld", (val & 0xffff));
break;
}
}
break;
case 'o':
- h8300_print_operand_address (file, x);
+ h8300_print_operand_address (file, VOIDmode, x);
break;
case 's':
if (GET_CODE (x) == CONST_INT)
case REG:
switch (GET_MODE (x))
{
- case QImode:
+ case E_QImode:
#if 0 /* Is it asm ("mov.b %0,r2l", ...) */
fprintf (file, "%s", byte_reg (x, 0));
#else /* ... or is it asm ("mov.b %0l,r2l", ...) */
fprintf (file, "%s", names_big[REGNO (x)]);
#endif
break;
- case HImode:
+ case E_HImode:
fprintf (file, "%s", names_big[REGNO (x)]);
break;
- case SImode:
- case SFmode:
+ case E_SImode:
+ case E_SFmode:
fprintf (file, "%s", names_extended[REGNO (x)]);
break;
default:
rtx addr = XEXP (x, 0);
fprintf (file, "@");
- output_address (addr);
+ output_address (GET_MODE (x), addr);
/* Add a length suffix to constant addresses. Although this
is often unnecessary, it helps to avoid ambiguity in the
break;
}
- /* Fall through. We should not get here if we are
- processing bit operations on H8/300 or H8/300H
- because 'U' constraint does not allow bit
- operations on the tiny area on these machines. */
+ /* FALLTHRU */
+
+ /* We should not get here if we are processing bit
+ operations on H8/300 or H8/300H because 'U'
+ constraint does not allow bit operations on the
+ tiny area on these machines. */
case 'X':
case 'T':
case CONST:
case LABEL_REF:
fprintf (file, "#");
- h8300_print_operand_address (file, x);
+ h8300_print_operand_address (file, VOIDmode, x);
break;
case CONST_DOUBLE:
{
long val;
- REAL_VALUE_TYPE rv;
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val);
fprintf (file, "#%ld", val);
break;
}
/* Output assembly language output for the address ADDR to FILE. */
static void
-h8300_print_operand_address (FILE *file, rtx addr)
+h8300_print_operand_address (FILE *file, machine_mode mode, rtx addr)
{
rtx index;
int size;
if (GET_CODE (index) == REG)
{
/* reg,foo */
- h8300_print_operand_address (file, XEXP (addr, 1));
+ h8300_print_operand_address (file, mode, XEXP (addr, 1));
fprintf (file, ",");
switch (size)
{
case 0:
- h8300_print_operand_address (file, index);
+ h8300_print_operand_address (file, mode, index);
break;
case 1:
else
{
/* foo+k */
- h8300_print_operand_address (file, XEXP (addr, 0));
+ h8300_print_operand_address (file, mode, XEXP (addr, 0));
fprintf (file, "+");
- h8300_print_operand_address (file, XEXP (addr, 1));
+ h8300_print_operand_address (file, mode, XEXP (addr, 1));
}
fprintf (file, ")");
break;
case LENGTH_TABLE_NONE:
gcc_unreachable ();
- case LENGTH_TABLE_ADDB:
- return h8300_binary_length (insn, &addb_length_table);
-
- case LENGTH_TABLE_ADDW:
- return h8300_binary_length (insn, &addw_length_table);
-
- case LENGTH_TABLE_ADDL:
- return h8300_binary_length (insn, &addl_length_table);
+ case LENGTH_TABLE_ADD:
+ if (GET_MODE (operands[0]) == QImode)
+ return h8300_binary_length (insn, &addb_length_table);
+ else if (GET_MODE (operands[0]) == HImode)
+ return h8300_binary_length (insn, &addw_length_table);
+ else if (GET_MODE (operands[0]) == SImode)
+ return h8300_binary_length (insn, &addl_length_table);
+ gcc_unreachable ();
case LENGTH_TABLE_LOGICB:
return h8300_binary_length (insn, &logicb_length_table);
switch (mode)
{
- case QImode:
+ case E_QImode:
if (addr == NULL_RTX)
return 2;
base_length = 4;
break;
- case HImode:
+ case E_HImode:
if (addr == NULL_RTX)
{
if (REG_P (src))
base_length = 4;
break;
- case SImode:
+ case E_SImode:
if (addr == NULL_RTX)
{
if (REG_P (src))
base_length = 8;
break;
- case SFmode:
+ case E_SFmode:
if (addr == NULL_RTX)
{
if (REG_P (src))
switch (mode)
{
- case QImode:
+ case E_QImode:
if (addr == NULL_RTX)
return 2;
base_length = 8;
break;
- case HImode:
+ case E_HImode:
if (addr == NULL_RTX)
{
if (REG_P (src))
base_length = 8;
break;
- case SImode:
+ case E_SImode:
if (addr == NULL_RTX)
{
if (REG_P (src))
base_length = 10;
break;
- case SFmode:
+ case E_SFmode:
if (addr == NULL_RTX)
{
if (REG_P (src))
switch (mode)
{
- case HImode:
+ case E_HImode:
/* First, see if we can finish with one insn. */
if ((TARGET_H8300H || TARGET_H8300S)
&& b0 != 0
}
}
break;
- case SImode:
+ case E_SImode:
if (TARGET_H8300H || TARGET_H8300S)
{
/* Determine if the lower half can be taken care of in no more
switch (mode)
{
- case HImode:
+ case E_HImode:
/* First, see if we can finish with one insn. */
if ((TARGET_H8300H || TARGET_H8300S)
&& b0 != 0
length += 2;
}
break;
- case SImode:
+ case E_SImode:
if (TARGET_H8300H || TARGET_H8300S)
{
/* Determine if the lower half can be taken care of in no more
switch (mode)
{
- case HImode:
+ case E_HImode:
/* First, see if we can finish with one insn. */
if ((TARGET_H8300H || TARGET_H8300S)
&& b0 != 0
cc = CC_SET_ZNV;
}
break;
- case SImode:
+ case E_SImode:
if (TARGET_H8300H || TARGET_H8300S)
{
/* Determine if the lower half can be taken care of in no more
goto end;
}
}
- else if ((8 <= count && count <= 13)
+ else if ((count >= 8 && count <= 13)
|| (TARGET_H8300S && count == 14))
{
info->remainder = count - 8;
gcc_unreachable ();
case SIshift:
- if (TARGET_H8300 && 8 <= count && count <= 9)
+ if (TARGET_H8300 && count >= 8 && count <= 9)
{
info->remainder = count - 8;
gcc_unreachable ();
}
}
- else if ((TARGET_H8300 && 16 <= count && count <= 20)
- || (TARGET_H8300H && 16 <= count && count <= 19)
- || (TARGET_H8300S && 16 <= count && count <= 21))
+ else if ((TARGET_H8300 && count >= 16 && count <= 20)
+ || (TARGET_H8300H && count >= 16 && count <= 19)
+ || (TARGET_H8300S && count >= 16 && count <= 21))
{
info->remainder = count - 16;
goto end;
}
}
- else if (TARGET_H8300 && 24 <= count && count <= 28)
+ else if (TARGET_H8300 && count >= 24 && count <= 28)
{
info->remainder = count - 24;
}
}
else if ((TARGET_H8300H && count == 24)
- || (TARGET_H8300S && 24 <= count && count <= 25))
+ || (TARGET_H8300S && count >= 24 && count <= 25))
{
info->remainder = count - 24;
/* Find the shift algorithm. */
switch (mode)
{
- case QImode:
+ case E_QImode:
a = shift_alg_qi[cpu][SHIFT_ASHIFT][count];
lr = shift_alg_qi[cpu][SHIFT_LSHIFTRT][count];
ar = shift_alg_qi[cpu][SHIFT_ASHIFTRT][count];
break;
- case HImode:
+ case E_HImode:
a = shift_alg_hi[cpu][SHIFT_ASHIFT][count];
lr = shift_alg_hi[cpu][SHIFT_LSHIFTRT][count];
ar = shift_alg_hi[cpu][SHIFT_ASHIFTRT][count];
break;
- case SImode:
+ case E_SImode:
a = shift_alg_si[cpu][SHIFT_ASHIFT][count];
lr = shift_alg_si[cpu][SHIFT_LSHIFTRT][count];
ar = shift_alg_si[cpu][SHIFT_ASHIFTRT][count];
switch (mode)
{
- case QImode:
+ case E_QImode:
shift_mode = QIshift;
break;
- case HImode:
+ case E_HImode:
shift_mode = HIshift;
break;
- case SImode:
+ case E_SImode:
shift_mode = SIshift;
break;
default:
/* Now mask off the high bits. */
switch (mode)
{
- case QImode:
+ case E_QImode:
sprintf (insn_buf, "and\t#%d,%%X0", mask);
break;
- case HImode:
+ case E_HImode:
gcc_assert (TARGET_H8300H || TARGET_H8300S);
sprintf (insn_buf, "and.w\t#%d,%%T0", mask);
break;
switch (mode)
{
- case QImode:
+ case E_QImode:
shift_mode = QIshift;
break;
- case HImode:
+ case E_HImode:
shift_mode = HIshift;
break;
- case SImode:
+ case E_SImode:
shift_mode = SIshift;
break;
default:
/* Now mask off the high bits. */
switch (mode)
{
- case QImode:
+ case E_QImode:
wlength += 1;
break;
- case HImode:
+ case E_HImode:
wlength += 2;
break;
- case SImode:
+ case E_SImode:
gcc_assert (!TARGET_H8300);
wlength += 3;
break;
switch (mode)
{
- case QImode:
+ case E_QImode:
shift_mode = QIshift;
break;
- case HImode:
+ case E_HImode:
shift_mode = HIshift;
break;
- case SImode:
+ case E_SImode:
shift_mode = SIshift;
break;
default:
/* Rotate by one bit. */
switch (mode)
{
- case QImode:
+ case E_QImode:
emit_insn (gen_rotlqi3_1 (dst, dst, const1_rtx));
break;
- case HImode:
+ case E_HImode:
emit_insn (gen_rotlhi3_1 (dst, dst, const1_rtx));
break;
- case SImode:
+ case E_SImode:
emit_insn (gen_rotlsi3_1 (dst, dst, const1_rtx));
break;
default:
/* Rotate by AMOUNT bits. */
switch (mode)
{
- case QImode:
+ case E_QImode:
emit_insn (gen_rotlqi3_1 (dst, dst, rotate_amount));
break;
- case HImode:
+ case E_HImode:
emit_insn (gen_rotlhi3_1 (dst, dst, rotate_amount));
break;
- case SImode:
+ case E_SImode:
emit_insn (gen_rotlsi3_1 (dst, dst, rotate_amount));
break;
default:
switch (mode)
{
- case QImode:
+ case E_QImode:
rotate_mode = QIshift;
break;
- case HImode:
+ case E_HImode:
rotate_mode = HIshift;
break;
- case SImode:
+ case E_SImode:
rotate_mode = SIshift;
break;
default:
{
switch (mode)
{
- case HImode:
+ case E_HImode:
/* This code works on any family. */
insn_buf = "xor.b\t%s0,%t0\n\txor.b\t%t0,%s0\n\txor.b\t%s0,%t0";
output_asm_insn (insn_buf, operands);
break;
- case SImode:
+ case E_SImode:
/* This code works on the H8/300H and H8S. */
insn_buf = "xor.w\t%e0,%f0\n\txor.w\t%f0,%e0\n\txor.w\t%e0,%f0";
output_asm_insn (insn_buf, operands);
static const struct attribute_spec h8300_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "interrupt_handler", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
- { "saveall", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
- { "OS_Task", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
- { "monitor", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
- { "function_vector", 0, 0, true, false, false,
- h8300_handle_fndecl_attribute, false },
- { "eightbit_data", 0, 0, true, false, false,
- h8300_handle_eightbit_data_attribute, false },
- { "tiny_data", 0, 0, true, false, false,
- h8300_handle_tiny_data_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "interrupt_handler", 0, 0, true, false, false, false,
+ h8300_handle_fndecl_attribute, NULL },
+ { "saveall", 0, 0, true, false, false, false,
+ h8300_handle_fndecl_attribute, NULL },
+ { "OS_Task", 0, 0, true, false, false, false,
+ h8300_handle_fndecl_attribute, NULL },
+ { "monitor", 0, 0, true, false, false, false,
+ h8300_handle_fndecl_attribute, NULL },
+ { "function_vector", 0, 0, true, false, false, false,
+ h8300_handle_fndecl_attribute, NULL },
+ { "eightbit_data", 0, 0, true, false, false, false,
+ h8300_handle_eightbit_data_attribute, NULL },
+ { "tiny_data", 0, 0, true, false, false, false,
+ h8300_handle_tiny_data_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
before I3. I3 is assumed to be a comparison insn. */
int
-same_cmp_preceding_p (rtx i3)
+same_cmp_preceding_p (rtx_insn *i3)
{
rtx_insn *i1, *i2;
after I1. I1 is assumed to be a comparison insn. */
int
-same_cmp_following_p (rtx i1)
+same_cmp_following_p (rtx_insn *i1)
{
rtx_insn *i2, *i3;
return 0;
}
-/* Worker function for HARD_REGNO_NREGS.
-
- We pretend the MAC register is 32bits -- we don't have any data
- types on the H8 series to handle more than 32bits. */
-
-int
-h8300_hard_regno_nregs (int regno ATTRIBUTE_UNUSED, machine_mode mode)
-{
- return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
-}
-
-/* Worker function for HARD_REGNO_MODE_OK. */
+/* Implement TARGET_HARD_REGNO_MODE_OK. */
-int
-h8300_hard_regno_mode_ok (int regno, machine_mode mode)
+static bool
+h8300_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
{
if (TARGET_H8300)
/* If an even reg, then anything goes. Otherwise the mode must be
return regno == MAC_REG ? mode == SImode : 1;
}
+/* Implement TARGET_MODES_TIEABLE_P. */
+
+static bool
+h8300_modes_tieable_p (machine_mode mode1, machine_mode mode2)
+{
+ return (mode1 == mode2
+ || ((mode1 == QImode
+ || mode1 == HImode
+ || ((TARGET_H8300H || TARGET_H8300S) && mode1 == SImode))
+ && (mode2 == QImode
+ || mode2 == HImode
+ || ((TARGET_H8300H || TARGET_H8300S) && mode2 == SImode))));
+}
+
/* Helper function for the move patterns. Make sure a move is legitimate. */
bool
emit_move_insn (mem, tem);
}
}
+
+/* Implement PUSH_ROUNDING.
+
+ On the H8/300, @-sp really pushes a byte if you ask it to - but that's
+ dangerous, so we claim that it always pushes a word, then we catch
+ the mov.b rx,@-sp and turn it into a mov.w rx,@-sp on output.
+
+ On the H8/300H, we simplify TARGET_QUICKCALL by setting this to 4
+ and doing a similar thing. */
+
+poly_int64
+h8300_push_rounding (poly_int64 bytes)
+{
+ return ((bytes + PARM_BOUNDARY / 8 - 1) & (-PARM_BOUNDARY / 8));
+}
\f
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#undef TARGET_HARD_REGNO_SCRATCH_OK
#define TARGET_HARD_REGNO_SCRATCH_OK h8300_hard_regno_scratch_ok
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK h8300_hard_regno_mode_ok
+
+#undef TARGET_MODES_TIEABLE_P
+#define TARGET_MODES_TIEABLE_P h8300_modes_tieable_p
+
+#undef TARGET_LRA_P
+#define TARGET_LRA_P hook_bool_void_false
+
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P h8300_legitimate_address_p
#undef TARGET_MODE_DEPENDENT_ADDRESS_P
#define TARGET_MODE_DEPENDENT_ADDRESS_P h8300_mode_dependent_address_p
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
struct gcc_target targetm = TARGET_INITIALIZER;