Mercurial > hg > CbC > CbC_gcc
diff gcc/config/h8300/h8300.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/config/h8300/h8300.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/config/h8300/h8300.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,7 +1,5 @@ /* Subroutines for insn-output.c for Renesas H8/300. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1992-2017 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com), Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com). @@ -24,27 +22,35 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.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 "hard-reg-set.h" -#include "insn-config.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 "conditions.h" #include "output.h" #include "insn-attr.h" #include "flags.h" -#include "recog.h" +#include "explow.h" #include "expr.h" -#include "function.h" -#include "optabs.h" -#include "diagnostic-core.h" -#include "c-family/c-pragma.h" /* ??? */ -#include "tm_p.h" -#include "ggc.h" -#include "target.h" +#include "tm-constrs.h" +#include "builtins.h" + +/* This file should be included last. */ #include "target-def.h" -#include "df.h" /* Classifies a h8300_src_operand or h8300_dst_operand. @@ -86,16 +92,18 @@ static void h8300_emit_stack_adjustment (int, HOST_WIDE_INT, bool); static HOST_WIDE_INT round_frame_size (HOST_WIDE_INT); static unsigned int compute_saved_regs (void); -static void push (int); -static void pop (int); static const char *cond_string (enum rtx_code); static unsigned int h8300_asm_insn_count (const char *); 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 *, 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 static void h8300_asm_named_section (const char *, unsigned int, tree); #endif +static int h8300_register_move_cost (machine_mode, reg_class_t, reg_class_t); static int h8300_and_costs (rtx); static int h8300_shift_costs (rtx); static void h8300_push_pop (int, int, bool, bool); @@ -109,10 +117,11 @@ static unsigned int h8300_unary_length (rtx); static unsigned int h8300_short_immediate_length (rtx); static unsigned int h8300_bitfield_length (rtx, rtx); -static unsigned int h8300_binary_length (rtx, const h8300_length_table *); +static unsigned int h8300_binary_length (rtx_insn *, const h8300_length_table *); static bool h8300_short_move_mem_p (rtx, enum rtx_code); static unsigned int h8300_move_length (rtx *, const h8300_length_table *); static bool h8300_hard_regno_scratch_ok (unsigned int); +static rtx h8300_get_index (rtx, machine_mode mode, int *); /* CPU_TYPE, says what cpu we're compiling for. */ int cpu_type; @@ -303,17 +312,6 @@ H8_S }; -/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ - -static const struct default_options h8300_option_optimization_table[] = - { - /* Basic block reordering is only beneficial on targets with cache - and/or variable-cycle branches where (cycle count taken != - cycle count not taken). */ - { OPT_LEVELS_ALL, OPT_freorder_blocks, NULL, 0 }, - { OPT_LEVELS_NONE, 0, NULL, 0 } - }; - /* Initialize various cpu specific globals at start up. */ static void @@ -323,6 +321,14 @@ static const char *const h8_pop_ops[2] = { "pop" , "pop.l" }; static const char *const h8_mov_ops[2] = { "mov.w", "mov.l" }; +#ifndef OBJECT_FORMAT_ELF + if (TARGET_H8300SX) + { + error ("-msx is not supported in coff"); + target_flags |= MASK_H8300S; + } +#endif + if (TARGET_H8300) { cpu_type = (int) CPU_H8300; @@ -346,10 +352,42 @@ if (TARGET_H8300 && TARGET_NORMAL_MODE) { - error ("-mn is used without -mh or -ms"); + 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"); + target_flags |= MASK_H8300S_1; + } + + if (TARGET_H8300 && TARGET_INT32) + { + 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"); + 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!"); + } + +#ifdef H8300_LINUX + if ((TARGET_NORMAL_MODE)) + { + error ("-mn is not supported for linux targets"); + target_flags ^= MASK_NORMAL_MODE; + } +#endif + /* Some of the shifts are optimized for speed by default. See http://gcc.gnu.org/ml/gcc-patches/2002-07/msg01858.html If optimizing for size, change shift_alg for those shift to @@ -416,75 +454,10 @@ } /* This target defaults to strict volatile bitfields. */ - if (flag_strict_volatile_bitfields < 0) + if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) flag_strict_volatile_bitfields = 1; } -/* Implement REG_CLASS_FROM_LETTER. - - Some patterns need to use er6 as a scratch register. This is - difficult to arrange since er6 is the frame pointer and usually - can't be spilled. - - Such patterns should define two alternatives, one which allows only - er6 and one which allows any general register. The former alternative - should have a 'd' constraint while the latter should be disparaged and - use 'D'. - - Normally, 'd' maps to DESTINATION_REGS and 'D' maps to GENERAL_REGS. - However, there are cases where they should be NO_REGS: - - - 'd' should be NO_REGS when reloading a function that uses the - frame pointer. In this case, DESTINATION_REGS won't contain any - spillable registers, so the first alternative can't be used. - - - -fno-omit-frame-pointer means that the frame pointer will - always be in use. It's therefore better to map 'd' to NO_REGS - before reload so that register allocator will pick the second - alternative. - - - we would like 'D' to be be NO_REGS when the frame pointer isn't - live, but we the frame pointer may turn out to be needed after - we start reload, and then we may have already decided we don't - have a choice, so we can't do that. Forcing the register - allocator to use er6 if possible might produce better code for - small functions: it's more efficient to save and restore er6 in - the prologue & epilogue than to do it in a define_split. - Hopefully disparaging 'D' will have a similar effect, without - forcing a reload failure if the frame pointer is found to be - needed too late. */ - -enum reg_class -h8300_reg_class_from_letter (int c) -{ - switch (c) - { - case 'a': - return MAC_REGS; - - case 'c': - return COUNTER_REGS; - - case 'd': - if (!flag_omit_frame_pointer && !reload_completed) - return NO_REGS; - if (frame_pointer_needed && reload_in_progress) - return NO_REGS; - return DESTINATION_REGS; - - case 'D': - /* The meaning of a constraint shouldn't change dynamically, so - we can't make this NO_REGS. */ - return GENERAL_REGS; - - case 'f': - return SOURCE_REGS; - - default: - return NO_REGS; - } -} - /* Return the byte register name for a register rtx X. B should be 0 if you want a lower byte register. B should be 1 if you want an upper byte register. */ @@ -520,11 +493,11 @@ handlers. */ \ || (h8300_current_function_interrupt_function_p () \ && call_used_regs[regno] \ - && !current_function_is_leaf))) + && !crtl->is_leaf))) /* We use this to wrap all emitted insns in the prologue. */ -static rtx -F (rtx x, bool set_it) +static rtx_insn * +F (rtx_insn *x, bool set_it) { if (set_it) RTX_FRAME_RELATED_P (x) = 1; @@ -544,7 +517,7 @@ int i; for (i = 0; i < len; i++) - F (XVECEXP (par, 0, i), true); + RTX_FRAME_RELATED_P (XVECEXP (par, 0, i)) = 1; return par; } @@ -581,8 +554,9 @@ the splitter will do. */ if (Pmode == HImode) { - rtx x = emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (sign * size))); + rtx_insn *x = emit_insn (gen_addhi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (sign * size))); if (size < 4) F (x, in_prologue); } @@ -626,8 +600,8 @@ /* Emit an insn to push register RN. */ -static void -push (int rn) +static rtx +push (int rn, bool in_prologue) { rtx reg = gen_rtx_REG (word_mode, rn); rtx x; @@ -638,13 +612,14 @@ x = gen_push_h8300hs_advanced (reg); else x = gen_push_h8300hs_normal (reg); - x = F (emit_insn (x), true); + x = F (emit_insn (x), in_prologue); add_reg_note (x, REG_INC, stack_pointer_rtx); + return x; } /* Emit an insn to pop register RN. */ -static void +static rtx pop (int rn) { rtx reg = gen_rtx_REG (word_mode, rn); @@ -658,6 +633,7 @@ x = gen_pop_h8300hs_normal (reg); x = emit_insn (x); add_reg_note (x, REG_INC, stack_pointer_rtx); + return x; } /* Emit an instruction to push or pop NREGS consecutive registers @@ -689,7 +665,7 @@ if (pop_p) pop (regno); else - push (regno); + push (regno, false); return; } @@ -702,7 +678,7 @@ /* Add the return instruction. */ if (return_p) { - RTVEC_ELT (vec, i) = gen_rtx_RETURN (VOIDmode); + RTVEC_ELT (vec, i) = ret_rtx; i++; } @@ -716,21 +692,21 @@ /* Register REGNO + NREGS - 1 is popped first. Before the stack adjustment, its slot is at address @sp. */ lhs = gen_rtx_REG (SImode, regno + j); - rhs = gen_rtx_MEM (SImode, plus_constant (sp, (nregs - j - 1) * 4)); + rhs = gen_rtx_MEM (SImode, plus_constant (Pmode, sp, + (nregs - j - 1) * 4)); } else { /* Register REGNO is pushed first and will be stored at @(-4,sp). */ - lhs = gen_rtx_MEM (SImode, plus_constant (sp, (j + 1) * -4)); + lhs = gen_rtx_MEM (SImode, plus_constant (Pmode, sp, (j + 1) * -4)); rhs = gen_rtx_REG (SImode, regno + j); } - RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, lhs, rhs); + RTVEC_ELT (vec, i + j) = gen_rtx_SET (lhs, rhs); } /* Add the stack adjustment. */ offset = GEN_INT ((pop_p ? nregs : -nregs) * 4); - RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, sp, - gen_rtx_PLUS (Pmode, sp, offset)); + RTVEC_ELT (vec, i + j) = gen_rtx_SET (sp, gen_rtx_PLUS (Pmode, sp, offset)); x = gen_rtx_PARALLEL (VOIDmode, vec); if (!pop_p) @@ -865,15 +841,15 @@ return; if (h8300_monitor_function_p (current_function_decl)) - /* My understanding of monitor functions is they act just like - interrupt functions, except the prologue must mask - interrupts. */ + /* The monitor function act as normal functions, which means it + can accept parameters and return values. In addition to this, + interrupts are masked in prologue and return with "rte" in epilogue. */ emit_insn (gen_monitor_prologue ()); if (frame_pointer_needed) { /* Push fp. */ - push (HARD_FRAME_POINTER_REGNUM); + push (HARD_FRAME_POINTER_REGNUM, true); F (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx), true); } @@ -906,6 +882,12 @@ /* Leave room for locals. */ h8300_emit_stack_adjustment (-1, round_frame_size (get_frame_size ()), true); + + if (flag_stack_usage_info) + current_function_static_stack_size + = round_frame_size (get_frame_size ()) + + (__builtin_popcount (saved_regs) * UNITS_PER_WORD) + + (frame_pointer_needed ? UNITS_PER_WORD : 0); } /* Return nonzero if we can use "rts" for the function currently being @@ -986,7 +968,7 @@ } if (!returned_p) - emit_jump_insn (gen_rtx_RETURN (VOIDmode)); + emit_jump_insn (ret_rtx); } /* Return nonzero if the current function is an interrupt @@ -995,8 +977,13 @@ int h8300_current_function_interrupt_function_p (void) { - return (h8300_interrupt_function_p (current_function_decl) - || h8300_monitor_function_p (current_function_decl)); + return (h8300_interrupt_function_p (current_function_decl)); +} + +int +h8300_current_function_monitor_function_p () +{ + return (h8300_monitor_function_p (current_function_decl)); } /* Output assembly code for the start of the file. */ @@ -1006,12 +993,12 @@ { default_file_start (); - if (TARGET_H8300H) - fputs (TARGET_NORMAL_MODE ? "\t.h8300hn\n" : "\t.h8300h\n", asm_out_file); - else if (TARGET_H8300SX) + if (TARGET_H8300SX) fputs (TARGET_NORMAL_MODE ? "\t.h8300sxn\n" : "\t.h8300sx\n", asm_out_file); else if (TARGET_H8300S) fputs (TARGET_NORMAL_MODE ? "\t.h8300sn\n" : "\t.h8300s\n", asm_out_file); + else if (TARGET_H8300H) + fputs (TARGET_NORMAL_MODE ? "\t.h8300hn\n" : "\t.h8300h\n", asm_out_file); } /* Output assembly language code for the end of file. */ @@ -1028,7 +1015,7 @@ instead of adds/subs. */ void -split_adds_subs (enum machine_mode mode, rtx *operands) +split_adds_subs (machine_mode mode, rtx *operands) { HOST_WIDE_INT val = INTVAL (operands[1]); rtx reg = operands[0]; @@ -1046,11 +1033,11 @@ switch (mode) { - case HImode: + case E_HImode: gen_add = gen_addhi3; break; - case SImode: + case E_SImode: gen_add = gen_addsi3; break; @@ -1101,9 +1088,11 @@ case the first 3 arguments are passed in registers. */ static rtx -h8300_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, +h8300_function_arg (cumulative_args_t cum_v, machine_mode mode, const_tree type, bool named) { + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + static const char *const hand_list[] = { "__main", "__cmpsi2", @@ -1172,15 +1161,33 @@ (TYPE is null for libcalls where that information may not be available.) */ static void -h8300_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, +h8300_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { + 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); } +/* Implements TARGET_REGISTER_MOVE_COST. + + Any SI register-to-register move may need to be reloaded, + so inmplement h8300_register_move_cost to return > 2 so that reload never + shortcuts. */ + +static int +h8300_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, + reg_class_t from, reg_class_t to) +{ + if (from == MAC_REGS || to == MAC_REG) + return 6; + else + return 3; +} + /* Compute the cost of an and insn. */ static int @@ -1224,8 +1231,11 @@ /* Worker function for TARGET_RTX_COSTS. */ static bool -h8300_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed) +h8300_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code, + int opno ATTRIBUTE_UNUSED, int *total, bool speed) { + int code = GET_CODE (x); + if (TARGET_H8300SX && outer_code == MEM) { /* Estimate the number of execution states needed to calculate @@ -1255,7 +1265,7 @@ *total = 0; return true; } - if (-4 <= n || n <= 4) + if (-4 <= n && n <= 4) { switch ((int) n) { @@ -1318,12 +1328,12 @@ 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; @@ -1337,12 +1347,12 @@ 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; @@ -1449,14 +1459,20 @@ /* Print operand X using operand code CODE to assembly language output file FILE. */ -void -print_operand (FILE *file, rtx x, int code) +static void +h8300_print_operand (FILE *file, rtx x, int code) { /* This is used for communication between codes V,W,Z and Y. */ static int bitint; switch (code) { + case 'C': + if (h8300_constant_length (x) == 2) + fprintf (file, ":16"); + else + fprintf (file, ":32"); + return; case 'E': switch (GET_CODE (x)) { @@ -1529,7 +1545,7 @@ if (GET_CODE (x) == REG) fprintf (file, "%s%c", names_big[REGNO (x)], bitint > 7 ? 'h' : 'l'); else - print_operand (file, x, 'R'); + h8300_print_operand (file, x, 'R'); bitint = -1; break; case 'Z': @@ -1562,7 +1578,7 @@ fprintf (file, "%s", names_upper_extended[REGNO (x)]); break; case MEM: - print_operand (file, x, 0); + h8300_print_operand (file, x, 0); break; case CONST_INT: fprintf (file, "#%ld", ((INTVAL (x) >> 16) & 0xffff)); @@ -1570,9 +1586,7 @@ 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; } @@ -1592,7 +1606,7 @@ break; case MEM: x = adjust_address (x, HImode, 2); - print_operand (file, x, 0); + h8300_print_operand (file, x, 0); break; case CONST_INT: fprintf (file, "#%ld", INTVAL (x) & 0xffff); @@ -1600,9 +1614,7 @@ 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; } @@ -1637,7 +1649,7 @@ } break; case 'o': - print_operand_address (file, x); + h8300_print_operand_address (file, VOIDmode, x); break; case 's': if (GET_CODE (x) == CONST_INT) @@ -1685,18 +1697,18 @@ 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: @@ -1709,7 +1721,7 @@ 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 @@ -1730,10 +1742,12 @@ 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': @@ -1754,14 +1768,12 @@ case CONST: case LABEL_REF: fprintf (file, "#"); - 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; } @@ -1771,10 +1783,18 @@ } } +/* Implements TARGET_PRINT_OPERAND_PUNCT_VALID_P. */ + +static bool +h8300_print_operand_punct_valid_p (unsigned char code) +{ + return (code == '#'); +} + /* Output assembly language output for the address ADDR to FILE. */ -void -print_operand_address (FILE *file, rtx addr) +static void +h8300_print_operand_address (FILE *file, machine_mode mode, rtx addr) { rtx index; int size; @@ -1808,37 +1828,37 @@ if (GET_CODE (index) == REG) { /* reg,foo */ - print_operand_address (file, XEXP (addr, 1)); + h8300_print_operand_address (file, mode, XEXP (addr, 1)); fprintf (file, ","); switch (size) { case 0: - print_operand_address (file, index); + h8300_print_operand_address (file, mode, index); break; case 1: - print_operand (file, index, 'X'); + h8300_print_operand (file, index, 'X'); fputs (".b", file); break; case 2: - print_operand (file, index, 'T'); + h8300_print_operand (file, index, 'T'); fputs (".w", file); break; case 4: - print_operand (file, index, 'S'); + h8300_print_operand (file, index, 'S'); fputs (".l", file); break; } - /* print_operand_address (file, XEXP (addr, 0)); */ + /* h8300_print_operand_address (file, XEXP (addr, 0)); */ } else { /* foo+k */ - print_operand_address (file, XEXP (addr, 0)); + h8300_print_operand_address (file, mode, XEXP (addr, 0)); fprintf (file, "+"); - print_operand_address (file, XEXP (addr, 1)); + h8300_print_operand_address (file, mode, XEXP (addr, 1)); } fprintf (file, ")"); break; @@ -1869,7 +1889,7 @@ option. */ void -final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED, +final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED, int num_operands ATTRIBUTE_UNUSED) { /* This holds the last insn address. */ @@ -2006,7 +2026,8 @@ else ret = gen_rtx_MEM (Pmode, memory_address (Pmode, - plus_constant (frame, UNITS_PER_WORD))); + plus_constant (Pmode, frame, + UNITS_PER_WORD))); set_mem_alias_set (ret, get_frame_alias_set ()); return ret; } @@ -2014,7 +2035,7 @@ /* Update the condition code from the insn. */ void -notice_update_cc (rtx body, rtx insn) +notice_update_cc (rtx body, rtx_insn *insn) { rtx set; @@ -2094,8 +2115,8 @@ MODE is the mode of the value being accessed. It can be VOIDmode if the address is known to be valid, but its mode is unknown. */ -rtx -h8300_get_index (rtx x, enum machine_mode mode, int *size) +static rtx +h8300_get_index (rtx x, machine_mode mode, int *size) { int dummy, factor; @@ -2156,6 +2177,22 @@ return x; } +/* Worker function for TARGET_MODE_DEPENDENT_ADDRESS_P. + + On the H8/300, the predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +static bool +h8300_mode_dependent_address_p (const_rtx addr, + addr_space_t as ATTRIBUTE_UNUSED) +{ + if (GET_CODE (addr) == PLUS + && h8300_get_index (XEXP (addr, 0), VOIDmode, 0) != XEXP (addr, 0)) + return true; + + return false; +} + static const h8300_length_table addb_length_table = { /* #xx Rs @aa @Rs @xx */ @@ -2416,7 +2453,7 @@ /* Calculate the length of general binary instruction INSN using TABLE. */ static unsigned int -h8300_binary_length (rtx insn, const h8300_length_table *table) +h8300_binary_length (rtx_insn *insn, const h8300_length_table *table) { rtx set; @@ -2505,7 +2542,7 @@ OPERANDS is the array of its operands. */ unsigned int -h8300_insn_length_from_table (rtx insn, rtx * operands) +h8300_insn_length_from_table (rtx_insn *insn, rtx * operands) { switch (get_attr_length_table (insn)) { @@ -2669,8 +2706,8 @@ first_dest = replace_equiv_address (dest, dest_reg); first_src = replace_equiv_address (src, src_reg); - set_mem_size (first_dest, GEN_INT (n & -factor)); - set_mem_size (first_src, GEN_INT (n & -factor)); + set_mem_size (first_dest, n & -factor); + set_mem_size (first_src, n & -factor); length = copy_to_mode_reg (HImode, gen_int_mode (n / factor, HImode)); emit_insn (gen_movmd (first_dest, first_src, length, GEN_INT (factor))); @@ -2705,11 +2742,20 @@ void h8300_swap_into_er6 (rtx addr) { - push (HARD_FRAME_POINTER_REGNUM); + rtx insn = push (HARD_FRAME_POINTER_REGNUM, false); + if (frame_pointer_needed) + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (Pmode, gen_rtx_MEM (Pmode, stack_pointer_rtx), + 2 * UNITS_PER_WORD)); + else + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, 4))); + emit_move_insn (hard_frame_pointer_rtx, addr); if (REGNO (addr) == SP_REG) emit_move_insn (hard_frame_pointer_rtx, - plus_constant (hard_frame_pointer_rtx, + plus_constant (Pmode, hard_frame_pointer_rtx, GET_MODE_SIZE (word_mode))); } @@ -2719,9 +2765,20 @@ void h8300_swap_out_of_er6 (rtx addr) { + rtx insn; + if (REGNO (addr) != SP_REG) emit_move_insn (addr, hard_frame_pointer_rtx); - pop (HARD_FRAME_POINTER_REGNUM); + + insn = pop (HARD_FRAME_POINTER_REGNUM); + if (frame_pointer_needed) + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (Pmode, hard_frame_pointer_rtx, + 2 * UNITS_PER_WORD)); + else + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, -4))); } /* Return the length of mov instruction. */ @@ -2733,7 +2790,7 @@ length, assuming the largest addressing mode is used, and then adjust later in the function. Otherwise, we compute and return the exact length in one step. */ - enum machine_mode mode = GET_MODE (operands[0]); + machine_mode mode = GET_MODE (operands[0]); rtx dest = operands[0]; rtx src = operands[1]; rtx addr; @@ -2751,7 +2808,7 @@ switch (mode) { - case QImode: + case E_QImode: if (addr == NULL_RTX) return 2; @@ -2763,7 +2820,7 @@ base_length = 4; break; - case HImode: + case E_HImode: if (addr == NULL_RTX) { if (REG_P (src)) @@ -2778,7 +2835,7 @@ base_length = 4; break; - case SImode: + case E_SImode: if (addr == NULL_RTX) { if (REG_P (src)) @@ -2805,13 +2862,13 @@ base_length = 8; break; - case SFmode: + case E_SFmode: if (addr == NULL_RTX) { if (REG_P (src)) return 4; - if (CONST_DOUBLE_OK_FOR_LETTER_P (src, 'G')) + if (satisfies_constraint_G (src)) return 4; return 8; @@ -2857,7 +2914,7 @@ switch (mode) { - case QImode: + case E_QImode: if (addr == NULL_RTX) return 2; @@ -2869,7 +2926,7 @@ base_length = 8; break; - case HImode: + case E_HImode: if (addr == NULL_RTX) { if (REG_P (src)) @@ -2884,7 +2941,7 @@ base_length = 8; break; - case SImode: + case E_SImode: if (addr == NULL_RTX) { if (REG_P (src)) @@ -2925,13 +2982,13 @@ base_length = 10; break; - case SFmode: + case E_SFmode: if (addr == NULL_RTX) { if (REG_P (src)) return 2; - if (CONST_DOUBLE_OK_FOR_LETTER_P (src, 'G')) + if (satisfies_constraint_G (src)) return 2; return 6; @@ -2983,7 +3040,7 @@ const char * output_plussi (rtx *operands) { - enum machine_mode mode = GET_MODE (operands[0]); + machine_mode mode = GET_MODE (operands[0]); gcc_assert (mode == SImode); @@ -3067,7 +3124,7 @@ unsigned int compute_plussi_length (rtx *operands) { - enum machine_mode mode = GET_MODE (operands[0]); + machine_mode mode = GET_MODE (operands[0]); gcc_assert (mode == SImode); @@ -3146,7 +3203,7 @@ enum attr_cc compute_plussi_cc (rtx *operands) { - enum machine_mode mode = GET_MODE (operands[0]); + machine_mode mode = GET_MODE (operands[0]); gcc_assert (mode == SImode); @@ -3201,7 +3258,7 @@ /* Output a logical insn. */ const char * -output_logical_op (enum machine_mode mode, rtx *operands) +output_logical_op (machine_mode mode, rtx *operands) { /* Figure out the logical op that we need to perform. */ enum rtx_code code = GET_CODE (operands[3]); @@ -3247,7 +3304,7 @@ switch (mode) { - case HImode: + case E_HImode: /* First, see if we can finish with one insn. */ if ((TARGET_H8300H || TARGET_H8300S) && b0 != 0 @@ -3272,7 +3329,7 @@ } } break; - case SImode: + case E_SImode: if (TARGET_H8300H || TARGET_H8300S) { /* Determine if the lower half can be taken care of in no more @@ -3382,7 +3439,7 @@ /* Compute the length of a logical insn. */ unsigned int -compute_logical_op_length (enum machine_mode mode, rtx *operands) +compute_logical_op_length (machine_mode mode, rtx *operands) { /* Figure out the logical op that we need to perform. */ enum rtx_code code = GET_CODE (operands[3]); @@ -3412,7 +3469,7 @@ switch (mode) { - case HImode: + case E_HImode: /* First, see if we can finish with one insn. */ if ((TARGET_H8300H || TARGET_H8300S) && b0 != 0 @@ -3432,7 +3489,7 @@ 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 @@ -3528,7 +3585,7 @@ /* Compute which flag bits are valid after a logical insn. */ enum attr_cc -compute_logical_op_cc (enum machine_mode mode, rtx *operands) +compute_logical_op_cc (machine_mode mode, rtx *operands) { /* Figure out the logical op that we need to perform. */ enum rtx_code code = GET_CODE (operands[3]); @@ -3556,7 +3613,7 @@ switch (mode) { - case HImode: + case E_HImode: /* First, see if we can finish with one insn. */ if ((TARGET_H8300H || TARGET_H8300S) && b0 != 0 @@ -3565,7 +3622,7 @@ 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 @@ -3619,13 +3676,13 @@ rtx tmp; tmp = gen_rtx_COMPARE (VOIDmode, op0, op1); - emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, tmp)); + emit_insn (gen_rtx_SET (cc0_rtx, tmp)); tmp = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, gen_rtx_LABEL_REF (VOIDmode, label), pc_rtx); - emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + emit_jump_insn (gen_rtx_SET (pc_rtx, tmp)); } @@ -3641,10 +3698,10 @@ rtx tmp; tmp = gen_rtx_COMPARE (VOIDmode, op0, op1); - emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, tmp)); + emit_insn (gen_rtx_SET (cc0_rtx, tmp)); tmp = gen_rtx_fmt_ee (code, GET_MODE (dest), cc0_rtx, const0_rtx); - emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); + emit_insn (gen_rtx_SET (dest, tmp)); } /* Shifts. @@ -3686,7 +3743,7 @@ /* Classify a shift with the given mode and code. OP is the shift amount. */ enum h8sx_shift_type -h8sx_classify_shift (enum machine_mode mode, enum rtx_code code, rtx op) +h8sx_classify_shift (machine_mode mode, enum rtx_code code, rtx op) { if (!TARGET_H8300SX) return H8SX_SHIFT_NONE; @@ -3731,7 +3788,7 @@ /* Return the asm template for a single h8sx shift instruction. OPERANDS[0] and OPERANDS[1] are the destination, OPERANDS[2] is the source and OPERANDS[3] is the shift. SUFFIX is the - size suffix ('b', 'w' or 'l') and OPTYPE is the print_operand + size suffix ('b', 'w' or 'l') and OPTYPE is the h8300_print_operand prefix for the destination operand. */ const char * @@ -3778,7 +3835,7 @@ /* Emit code to do shifts. */ bool -expand_a_shift (enum machine_mode mode, enum rtx_code code, rtx operands[]) +expand_a_shift (machine_mode mode, enum rtx_code code, rtx operands[]) { switch (h8sx_classify_shift (mode, code, operands[2])) { @@ -3801,7 +3858,7 @@ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, - gen_rtx_SET (VOIDmode, copy_rtx (operands[0]), + gen_rtx_SET (copy_rtx (operands[0]), gen_rtx_fmt_ee (code, mode, copy_rtx (operands[0]), operands[2])), gen_rtx_CLOBBER (VOIDmode, @@ -4022,10 +4079,10 @@ /* Find the target CPU. */ if (TARGET_H8300) cpu = H8_300; - else if (TARGET_H8300H) + else if (TARGET_H8300S) + cpu = H8_S; + else cpu = H8_300H; - else - cpu = H8_S; /* Find the shift algorithm. */ info->alg = SHIFT_LOOP; @@ -4311,7 +4368,7 @@ info->cc_inline = CC_SET_ZNV; goto end; case SHIFT_ASHIFTRT: - info->special = "mov.b\t%z0,%w0\n\tbld\t#7,%w0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0"; + info->special = "mov.b\t%z0,%w0\n\tbld\t#7,%w0\n\tsubx\t%x0,%x0\n\tsubx\t%y0,%y0\n\tsubx\t%z0,%z0"; info->shift1 = "shar.b\t%w0"; info->cc_inline = CC_SET_ZNV; goto end; @@ -4457,7 +4514,7 @@ needed for some shift with COUNT and MODE. Return 0 otherwise. */ int -h8300_shift_needs_scratch_p (int count, enum machine_mode mode) +h8300_shift_needs_scratch_p (int count, machine_mode mode) { enum h8_cpu cpu; int a, lr, ar; @@ -4468,27 +4525,27 @@ /* Find out the target CPU. */ if (TARGET_H8300) cpu = H8_300; - else if (TARGET_H8300H) + else if (TARGET_H8300S) + cpu = H8_S; + else cpu = H8_300H; - else - cpu = H8_S; /* 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]; @@ -4510,7 +4567,7 @@ { static int loopend_lab; rtx shift = operands[3]; - enum machine_mode mode = GET_MODE (shift); + machine_mode mode = GET_MODE (shift); enum rtx_code code = GET_CODE (shift); enum shift_type shift_type; enum shift_mode shift_mode; @@ -4521,13 +4578,13 @@ 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: @@ -4613,11 +4670,11 @@ /* 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; @@ -4680,7 +4737,7 @@ compute_a_shift_length (rtx insn ATTRIBUTE_UNUSED, rtx *operands) { rtx shift = operands[3]; - enum machine_mode mode = GET_MODE (shift); + machine_mode mode = GET_MODE (shift); enum rtx_code code = GET_CODE (shift); enum shift_type shift_type; enum shift_mode shift_mode; @@ -4689,13 +4746,13 @@ 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: @@ -4785,13 +4842,13 @@ /* 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; @@ -4828,7 +4885,7 @@ compute_a_shift_cc (rtx insn ATTRIBUTE_UNUSED, rtx *operands) { rtx shift = operands[3]; - enum machine_mode mode = GET_MODE (shift); + machine_mode mode = GET_MODE (shift); enum rtx_code code = GET_CODE (shift); enum shift_type shift_type; enum shift_mode shift_mode; @@ -4837,13 +4894,13 @@ 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: @@ -4923,7 +4980,7 @@ rtx dst = operands[0]; rtx src = operands[1]; rtx rotate_amount = operands[2]; - enum machine_mode mode = GET_MODE (dst); + machine_mode mode = GET_MODE (dst); if (h8sx_classify_shift (mode, ROTATE, rotate_amount) == H8SX_SHIFT_UNARY) return false; @@ -4934,8 +4991,8 @@ if (GET_CODE (rotate_amount) != CONST_INT) { rtx counter = gen_reg_rtx (QImode); - rtx start_label = gen_label_rtx (); - rtx end_label = gen_label_rtx (); + rtx_code_label *start_label = gen_label_rtx (); + rtx_code_label *end_label = gen_label_rtx (); /* If the rotate amount is less than or equal to 0, we go out of the loop. */ @@ -4950,13 +5007,13 @@ /* 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: @@ -4978,13 +5035,13 @@ /* 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: @@ -5007,19 +5064,19 @@ const char *insn_buf; int bits; int amount; - enum machine_mode mode = GET_MODE (dst); + machine_mode mode = GET_MODE (dst); gcc_assert (GET_CODE (rotate_amount) == CONST_INT); 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: @@ -5066,13 +5123,13 @@ { 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); @@ -5110,7 +5167,7 @@ { rtx src = operands[1]; rtx amount_rtx = operands[2]; - enum machine_mode mode = GET_MODE (src); + machine_mode mode = GET_MODE (src); int amount; unsigned int length = 0; @@ -5170,7 +5227,7 @@ { /* OK to have a memory dest. */ if (GET_CODE (operands[0]) == MEM - && !OK_FOR_U (operands[0])) + && !satisfies_constraint_U (operands[0])) { rtx mem = gen_rtx_MEM (GET_MODE (operands[0]), copy_to_mode_reg (Pmode, @@ -5180,7 +5237,7 @@ } if (GET_CODE (operands[1]) == MEM - && !OK_FOR_U (operands[1])) + && !satisfies_constraint_U (operands[1])) { rtx mem = gen_rtx_MEM (GET_MODE (operands[1]), copy_to_mode_reg (Pmode, @@ -5367,15 +5424,23 @@ static const struct attribute_spec h8300_attribute_table[] = { - /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ - { "interrupt_handler", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, - { "saveall", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, - { "OS_Task", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, - { "monitor", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, - { "function_vector", 0, 0, true, false, false, h8300_handle_fndecl_attribute }, - { "eightbit_data", 0, 0, true, false, false, h8300_handle_eightbit_data_attribute }, - { "tiny_data", 0, 0, true, false, false, h8300_handle_tiny_data_attribute }, - { NULL, 0, 0, false, false, false, NULL } + /* { 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 } }; @@ -5409,7 +5474,7 @@ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) { - DECL_SECTION_NAME (decl) = build_string (7, ".eight"); + set_decl_section_name (decl, ".eight"); } else { @@ -5433,7 +5498,7 @@ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) { - DECL_SECTION_NAME (decl) = build_string (6, ".tiny"); + set_decl_section_name (decl, ".tiny"); } else { @@ -5556,6 +5621,12 @@ if (GET_CODE (x) == SYMBOL_REF) return (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_EIGHTBIT_DATA) != 0; + if (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF + && (SYMBOL_REF_FLAGS (XEXP (XEXP (x, 0), 0)) & SYMBOL_FLAG_EIGHTBIT_DATA) != 0) + return 1; + if (GET_CODE (x) != CONST_INT) return 0; @@ -5663,16 +5734,16 @@ 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 i1, i2; + rtx_insn *i1, *i2; /* Make sure we have a sequence of three insns. */ i2 = prev_nonnote_insn (i3); - if (i2 == NULL_RTX) + if (i2 == NULL) return 0; i1 = prev_nonnote_insn (i2); - if (i1 == NULL_RTX) + if (i1 == NULL) return 0; return (INSN_P (i1) && rtx_equal_p (PATTERN (i1), PATTERN (i3)) @@ -5683,16 +5754,16 @@ 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 i2, i3; + rtx_insn *i2, *i3; /* Make sure we have a sequence of three insns. */ i2 = next_nonnote_insn (i1); - if (i2 == NULL_RTX) + if (i2 == NULL) return 0; i3 = next_nonnote_insn (i2); - if (i3 == NULL_RTX) + if (i3 == NULL) return 0; return (INSN_P (i3) && rtx_equal_p (PATTERN (i1), PATTERN (i3)) @@ -5761,14 +5832,6 @@ } -/* Return nonzero if X is a legitimate constant. */ - -int -h8300_legitimate_constant_p (rtx x ATTRIBUTE_UNUSED) -{ - return 1; -} - /* Return nonzero if X is a REG or SUBREG suitable as a base register. */ static int @@ -5789,7 +5852,7 @@ CONSTANT_ADDRESS. */ static bool -h8300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +h8300_legitimate_address_p (machine_mode mode, rtx x, bool strict) { /* The register indirect addresses like @er0 is always valid. */ if (h8300_rtx_ok_for_base_p (x, strict)) @@ -5815,21 +5878,10 @@ 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, enum machine_mode mode) -{ - return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -} - -/* Worker function for HARD_REGNO_MODE_OK. */ - -int -h8300_hard_regno_mode_ok (int regno, enum machine_mode mode) +/* Implement TARGET_HARD_REGNO_MODE_OK. */ + +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 @@ -5840,6 +5892,54 @@ goes. */ 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 +h8300_move_ok (rtx dest, rtx src) +{ + rtx addr, other; + + /* Validate that at least one operand is a register. */ + if (MEM_P (dest)) + { + if (MEM_P (src) || CONSTANT_P (src)) + return false; + addr = XEXP (dest, 0); + other = src; + } + else if (MEM_P (src)) + { + addr = XEXP (src, 0); + other = dest; + } + else + return true; + + /* Validate that auto-inc doesn't affect OTHER. */ + if (GET_RTX_CLASS (GET_CODE (addr)) != RTX_AUTOINC) + return true; + addr = XEXP (addr, 0); + + if (addr == stack_pointer_rtx) + return register_no_sp_elim_operand (other, VOIDmode); + else + return !reg_overlap_mentioned_p(other, addr); +} /* Perform target dependent optabs initialization. */ static void @@ -5852,6 +5952,38 @@ set_optab_libfunc (umod_optab, HImode, "__umodhi3"); } +/* Worker function for TARGET_FUNCTION_VALUE. + + On the H8 the return value is in R0/R1. */ + +static rtx +h8300_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (ret_type), R0_REG); +} + +/* Worker function for TARGET_LIBCALL_VALUE. + + On the H8 the return value is in R0/R1. */ + +static rtx +h8300_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (mode, R0_REG); +} + +/* Worker function for TARGET_FUNCTION_VALUE_REGNO_P. + + On the H8, R0 is the only register thus used. */ + +static bool +h8300_function_value_regno_p (const unsigned int regno) +{ + return (regno == R0_REG); +} + /* Worker function for TARGET_RETURN_IN_MEMORY. */ static bool @@ -5926,18 +6058,37 @@ #undef TARGET_ASM_FILE_END #define TARGET_ASM_FILE_END h8300_file_end +#undef TARGET_PRINT_OPERAND +#define TARGET_PRINT_OPERAND h8300_print_operand +#undef TARGET_PRINT_OPERAND_ADDRESS +#define TARGET_PRINT_OPERAND_ADDRESS h8300_print_operand_address +#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P h8300_print_operand_punct_valid_p + #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO h8300_encode_section_info #undef TARGET_INSERT_ATTRIBUTES #define TARGET_INSERT_ATTRIBUTES h8300_insert_attributes +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST h8300_register_move_cost + #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS h8300_rtx_costs #undef TARGET_INIT_LIBFUNCS #define TARGET_INIT_LIBFUNCS h8300_init_libfuncs +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE h8300_function_value + +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE h8300_libcall_value + +#undef TARGET_FUNCTION_VALUE_REGNO_P +#define TARGET_FUNCTION_VALUE_REGNO_P h8300_function_value_regno_p + #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY h8300_return_in_memory @@ -5953,12 +6104,18 @@ #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_DEFAULT_TARGET_FLAGS -#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT - #undef TARGET_CAN_ELIMINATE #define TARGET_CAN_ELIMINATE h8300_can_eliminate @@ -5971,10 +6128,7 @@ #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE h8300_option_override -#undef TARGET_OPTION_OPTIMIZATION_TABLE -#define TARGET_OPTION_OPTIMIZATION_TABLE h8300_option_optimization_table - -#undef TARGET_EXCEPT_UNWIND_INFO -#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info +#undef TARGET_MODE_DEPENDENT_ADDRESS_P +#define TARGET_MODE_DEPENDENT_ADDRESS_P h8300_mode_dependent_address_p struct gcc_target targetm = TARGET_INITIALIZER;