Mercurial > hg > CbC > CbC_gcc
diff gcc/config/mn10300/mn10300.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/mn10300/mn10300.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/config/mn10300/mn10300.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,5 @@ /* Subroutines for insn-output.c for Matsushita MN10300 series - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 1996-2017 Free Software Foundation, Inc. Contributed by Jeff Law (law@cygnus.com). This file is part of GCC. @@ -22,28 +21,38 @@ #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 "stringpool.h" +#include "attribs.h" +#include "cfghooks.h" +#include "cfgloop.h" +#include "df.h" +#include "memmodel.h" +#include "tm_p.h" +#include "optabs.h" #include "regs.h" -#include "hard-reg-set.h" -#include "insn-config.h" -#include "conditions.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 "output.h" #include "insn-attr.h" -#include "flags.h" -#include "recog.h" #include "reload.h" +#include "explow.h" #include "expr.h" -#include "optabs.h" -#include "function.h" -#include "obstack.h" -#include "diagnostic-core.h" -#include "tm_p.h" #include "tm-constrs.h" -#include "target.h" +#include "cfgrtl.h" +#include "dumpfile.h" +#include "builtins.h" + +/* This file should be included last. */ #include "target-def.h" -#include "df.h" /* This is used in the am33_2.0-linux-gnu port, in which global symbol names are not prefixed by underscores, to tell whether to prefix a @@ -51,76 +60,18 @@ symbol names from register names. */ int mn10300_protect_label; -/* The selected processor. */ -enum processor_type mn10300_processor = PROCESSOR_DEFAULT; - -/* Processor type to select for tuning. */ -static const char * mn10300_tune_string = NULL; - /* Selected processor type for tuning. */ enum processor_type mn10300_tune_cpu = PROCESSOR_DEFAULT; -/* The size of the callee register save area. Right now we save everything - on entry since it costs us nothing in code size. It does cost us from a - speed standpoint, so we want to optimize this sooner or later. */ -#define REG_SAVE_BYTES (4 * df_regs_ever_live_p (2) \ - + 4 * df_regs_ever_live_p (3) \ - + 4 * df_regs_ever_live_p (6) \ - + 4 * df_regs_ever_live_p (7) \ - + 16 * (df_regs_ever_live_p (14) \ - || df_regs_ever_live_p (15) \ - || df_regs_ever_live_p (16) \ - || df_regs_ever_live_p (17))) - -/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ -static const struct default_options mn10300_option_optimization_table[] = - { - { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, - { OPT_LEVELS_NONE, 0, NULL, 0 } - }; - #define CC_FLAG_Z 1 #define CC_FLAG_N 2 #define CC_FLAG_C 4 #define CC_FLAG_V 8 -static int cc_flags_for_mode(enum machine_mode); +static int cc_flags_for_mode(machine_mode); static int cc_flags_for_code(enum rtx_code); -/* Implement TARGET_HANDLE_OPTION. */ - -static bool -mn10300_handle_option (size_t code, - const char *arg ATTRIBUTE_UNUSED, - int value) -{ - switch (code) - { - case OPT_mam33: - mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300; - return true; - - case OPT_mam33_2: - mn10300_processor = (value - ? PROCESSOR_AM33_2 - : MIN (PROCESSOR_AM33, PROCESSOR_DEFAULT)); - return true; - - case OPT_mam34: - mn10300_processor = (value ? PROCESSOR_AM34 : PROCESSOR_DEFAULT); - return true; - - case OPT_mtune_: - mn10300_tune_string = arg; - return true; - - default: - return true; - } -} - /* Implement TARGET_OPTION_OVERRIDE. */ - static void mn10300_option_override (void) { @@ -198,7 +149,7 @@ case 'B': { enum rtx_code cmp = GET_CODE (x); - enum machine_mode mode = GET_MODE (XEXP (x, 0)); + machine_mode mode = GET_MODE (XEXP (x, 0)); const char *str; int have_flags; @@ -291,7 +242,7 @@ { case MEM: fputc ('(', file); - output_address (XEXP (x, 0)); + output_address (GET_MODE (x), XEXP (x, 0)); fputc (')', file); break; @@ -310,7 +261,7 @@ { case MEM: fputc ('(', file); - output_address (XEXP (x, 0)); + output_address (GET_MODE (x), XEXP (x, 0)); fputc (')', file); break; @@ -325,22 +276,21 @@ case CONST_DOUBLE: { long val[2]; - REAL_VALUE_TYPE rv; switch (GET_MODE (x)) { - case DFmode: - REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_DOUBLE (rv, val); + case E_DFmode: + REAL_VALUE_TO_TARGET_DOUBLE + (*CONST_DOUBLE_REAL_VALUE (x), val); fprintf (file, "0x%lx", val[0]); break;; - case SFmode: - REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]); + case E_SFmode: + REAL_VALUE_TO_TARGET_SINGLE + (*CONST_DOUBLE_REAL_VALUE (x), val[0]); fprintf (file, "0x%lx", val[0]); break;; - case VOIDmode: - case DImode: + case E_VOIDmode: + case E_DImode: mn10300_print_operand_address (file, GEN_INT (CONST_DOUBLE_LOW (x))); break; @@ -370,7 +320,7 @@ case MEM: fputc ('(', file); x = adjust_address (x, SImode, 4); - output_address (XEXP (x, 0)); + output_address (GET_MODE (x), XEXP (x, 0)); fputc (')', file); break; @@ -385,19 +335,18 @@ case CONST_DOUBLE: { long val[2]; - REAL_VALUE_TYPE rv; switch (GET_MODE (x)) { - case DFmode: - REAL_VALUE_FROM_CONST_DOUBLE (rv, x); - REAL_VALUE_TO_TARGET_DOUBLE (rv, val); + case E_DFmode: + REAL_VALUE_TO_TARGET_DOUBLE + (*CONST_DOUBLE_REAL_VALUE (x), val); fprintf (file, "0x%lx", val[1]); break;; - case SFmode: + case E_SFmode: gcc_unreachable (); - case VOIDmode: - case DImode: + case E_VOIDmode: + case E_DImode: mn10300_print_operand_address (file, GEN_INT (CONST_DOUBLE_HIGH (x))); break; @@ -423,9 +372,10 @@ case 'A': fputc ('(', file); if (REG_P (XEXP (x, 0))) - output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx)); + output_address (VOIDmode, gen_rtx_PLUS (SImode, + XEXP (x, 0), const0_rtx)); else - output_address (XEXP (x, 0)); + output_address (VOIDmode, XEXP (x, 0)); fputc (')', file); break; @@ -456,12 +406,12 @@ { case MEM: fputc ('(', file); - output_address (XEXP (x, 0)); + output_address (GET_MODE (x), XEXP (x, 0)); fputc (')', file); break; case PLUS: - output_address (x); + output_address (VOIDmode, x); break; case REG: @@ -476,10 +426,8 @@ case CONST_DOUBLE: { unsigned 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, "0x%lx", val); break; } @@ -677,20 +625,36 @@ /* Returns the set of live, callee-saved registers as a bitmask. The callee-saved extended registers cannot be stored individually, so - all of them will be included in the mask if any one of them is used. */ - -int -mn10300_get_live_callee_saved_regs (void) + all of them will be included in the mask if any one of them is used. + Also returns the number of bytes in the registers in the mask if + BYTES_SAVED is not NULL. */ + +unsigned int +mn10300_get_live_callee_saved_regs (unsigned int * bytes_saved) { int mask; int i; - - mask = 0; + unsigned int count; + + count = mask = 0; for (i = 0; i <= LAST_EXTENDED_REGNUM; i++) if (df_regs_ever_live_p (i) && ! call_really_used_regs[i]) - mask |= (1 << i); + { + mask |= (1 << i); + ++ count; + } + if ((mask & 0x3c000) != 0) - mask |= 0x3c000; + { + for (i = 0x04000; i < 0x40000; i <<= 1) + if ((mask & i) == 0) + ++ count; + + mask |= 0x3c000; + } + + if (bytes_saved) + * bytes_saved = count * UNITS_PER_WORD; return mask; } @@ -754,9 +718,9 @@ continue; ++count; - x = plus_constant (stack_pointer_rtx, count * -4); + x = plus_constant (Pmode, stack_pointer_rtx, count * -4); x = gen_frame_mem (SImode, x); - x = gen_rtx_SET (VOIDmode, x, gen_rtx_REG (SImode, regno)); + x = gen_rtx_SET (x, gen_rtx_REG (SImode, regno)); elts[count] = F(x); /* Remove the register from the mask so that... */ @@ -768,8 +732,8 @@ gcc_assert (mask == 0); /* Create the instruction that updates the stack pointer. */ - x = plus_constant (stack_pointer_rtx, count * -4); - x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x); + x = plus_constant (Pmode, stack_pointer_rtx, count * -4); + x = gen_rtx_SET (stack_pointer_rtx, x); elts[0] = F(x); /* We need one PARALLEL element to update the stack pointer and @@ -778,13 +742,31 @@ F (emit_insn (x)); } +static inline unsigned int +popcount (unsigned int mask) +{ + unsigned int count = 0; + + while (mask) + { + ++ count; + mask &= ~ (mask & - mask); + } + return count; +} + void mn10300_expand_prologue (void) { HOST_WIDE_INT size = mn10300_frame_size (); - + unsigned int mask; + + mask = mn10300_get_live_callee_saved_regs (NULL); /* If we use any of the callee-saved registers, save them now. */ - mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ()); + mn10300_gen_multiple_store (mask); + + if (flag_stack_usage_info) + current_function_static_stack_size = size + popcount (mask) * 4; if (TARGET_AM33_2 && fp_regs_to_save ()) { @@ -801,6 +783,9 @@ unsigned int strategy_size = (unsigned)-1, this_strategy_size; rtx reg; + if (flag_stack_usage_info) + current_function_static_stack_size += num_regs_to_save * 4; + /* We have several different strategies to save FP registers. We can store them using SP offsets, which is beneficial if there are just a few registers to save, or we can use `a0' in @@ -1041,8 +1026,10 @@ mn10300_expand_epilogue (void) { HOST_WIDE_INT size = mn10300_frame_size (); - int reg_save_bytes = REG_SAVE_BYTES; - + unsigned int reg_save_bytes; + + mn10300_get_live_callee_saved_regs (& reg_save_bytes); + if (TARGET_AM33_2 && fp_regs_to_save ()) { int num_regs_to_save = fp_regs_to_save (), i; @@ -1112,7 +1099,7 @@ /* Insn: add size + 4 * num_regs_to_save + reg_save_bytes - 252,sp. */ this_strategy_size = SIZE_ADD_SP (size + 4 * num_regs_to_save - + reg_save_bytes - 252); + + (int) reg_save_bytes - 252); /* Insn: fmov (##,sp),fs#, fo each fs# to be restored. */ this_strategy_size += SIZE_FMOV_SP (252 - reg_save_bytes - 4 * num_regs_to_save, @@ -1260,9 +1247,9 @@ /* Adjust the stack and restore callee-saved registers, if any. */ if (mn10300_can_use_rets_insn ()) - emit_jump_insn (gen_rtx_RETURN (VOIDmode)); + emit_jump_insn (ret_rtx); else - emit_jump_insn (gen_return_ret (GEN_INT (size + REG_SAVE_BYTES))); + emit_jump_insn (gen_return_ret (GEN_INT (size + reg_save_bytes))); } /* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store(). @@ -1270,9 +1257,8 @@ parallel. If OP is a multiple store, return a mask indicating which registers it saves. Return 0 otherwise. */ -int -mn10300_store_multiple_operation (rtx op, - enum machine_mode mode ATTRIBUTE_UNUSED) +unsigned int +mn10300_store_multiple_regs (rtx op) { int count; int mask; @@ -1369,7 +1355,7 @@ static reg_class_t mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, - enum machine_mode mode, secondary_reload_info *sri) + machine_mode mode, secondary_reload_info *sri) { enum reg_class rclass = (enum reg_class) rclass_i; enum reg_class xclass = NO_REGS; @@ -1435,7 +1421,7 @@ if (xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM) { - addr = reg_equiv_mem [xregno]; + addr = reg_equiv_mem (xregno); if (addr) addr = XEXP (addr, 0); } @@ -1445,7 +1431,6 @@ if (addr && CONSTANT_ADDRESS_P (addr)) return GENERAL_REGS; } - /* Otherwise assume no secondary reloads are needed. */ return NO_REGS; } @@ -1477,7 +1462,10 @@ is the size of the callee register save area. */ if (from == ARG_POINTER_REGNUM) { - diff += REG_SAVE_BYTES; + unsigned int reg_save_bytes; + + mn10300_get_live_callee_saved_regs (& reg_save_bytes); + diff += reg_save_bytes; diff += 4 * fp_regs_to_save (); } @@ -1507,7 +1495,7 @@ alias_set_type set = get_varargs_alias_set (); if (argadj) - offset = plus_constant (crtl->args.arg_offset_rtx, argadj); + offset = plus_constant (Pmode, crtl->args.arg_offset_rtx, argadj); else offset = crtl->args.arg_offset_rtx; @@ -1516,7 +1504,8 @@ emit_move_insn (mem, gen_rtx_REG (SImode, 0)); mem = gen_rtx_MEM (SImode, - plus_constant (crtl->args.internal_arg_pointer, 4)); + plus_constant (Pmode, + crtl->args.internal_arg_pointer, 4)); set_mem_alias_set (mem, set); emit_move_insn (mem, gen_rtx_REG (SImode, 1)); @@ -1535,8 +1524,8 @@ /* Return true when a parameter should be passed by reference. */ static bool -mn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, - enum machine_mode mode, const_tree type, +mn10300_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED, + machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { unsigned HOST_WIDE_INT size; @@ -1553,9 +1542,10 @@ from a function. If the result is NULL_RTX, the argument is pushed. */ static rtx -mn10300_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, +mn10300_function_arg (cumulative_args_t cum_v, machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); rtx result = NULL_RTX; int size; @@ -1601,9 +1591,11 @@ (TYPE is null for libcalls where that information may not be available.) */ static void -mn10300_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, +mn10300_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) + 3) & ~3 : (int_size_in_bytes (type) + 3) & ~3); @@ -1613,9 +1605,10 @@ partially in registers and partially in memory. */ static int -mn10300_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, +mn10300_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) { + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); int size; /* We only support using 2 data registers as argument registers. */ @@ -1658,7 +1651,7 @@ bool outgoing) { rtx rv; - enum machine_mode mode = TYPE_MODE (valtype); + machine_mode mode = TYPE_MODE (valtype); if (! POINTER_TYPE_P (valtype)) return gen_rtx_REG (mode, FIRST_DATA_REGNUM); @@ -1682,7 +1675,7 @@ /* Implements TARGET_LIBCALL_VALUE. */ static rtx -mn10300_libcall_value (enum machine_mode mode, +mn10300_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) { return gen_rtx_REG (mode, FIRST_DATA_REGNUM); @@ -1794,7 +1787,7 @@ int mn10300_symbolic_operand (rtx op, - enum machine_mode mode ATTRIBUTE_UNUSED) + machine_mode mode ATTRIBUTE_UNUSED) { switch (GET_CODE (op)) { @@ -1826,7 +1819,7 @@ static rtx mn10300_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) + machine_mode mode ATTRIBUTE_UNUSED) { if (flag_pic && ! mn10300_legitimate_pic_operand_p (x)) x = mn10300_legitimize_pic_address (oldx, NULL_RTX); @@ -1869,6 +1862,7 @@ mn10300_legitimize_pic_address (rtx orig, rtx reg) { rtx x; + rtx_insn *insn; if (GET_CODE (orig) == LABEL_REF || (GET_CODE (orig) == SYMBOL_REF @@ -1882,7 +1876,7 @@ x = gen_rtx_CONST (SImode, x); emit_move_insn (reg, x); - x = emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx)); + insn = emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx)); } else if (GET_CODE (orig) == SYMBOL_REF) { @@ -1894,12 +1888,12 @@ x = gen_rtx_PLUS (SImode, pic_offset_table_rtx, x); x = gen_const_mem (SImode, x); - x = emit_move_insn (reg, x); + insn = emit_move_insn (reg, x); } else return orig; - set_unique_reg_note (x, REG_EQUAL, orig); + set_unique_reg_note (insn, REG_EQUAL, orig); return reg; } @@ -1957,7 +1951,7 @@ function record_unscaled_index_insn_codes. */ static bool -mn10300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +mn10300_legitimate_address_p (machine_mode mode, rtx x, bool strict) { rtx base, index; @@ -2025,7 +2019,7 @@ rtx mn10300_legitimize_reload_address (rtx x, - enum machine_mode mode ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, int opnum, int type, int ind_levels ATTRIBUTE_UNUSED) { @@ -2056,13 +2050,13 @@ return any_change ? x : NULL_RTX; } -/* Used by LEGITIMATE_CONSTANT_P(). Returns TRUE if X is a valid +/* Implement TARGET_LEGITIMATE_CONSTANT_P. Returns TRUE if X is a valid constant. Note that some "constants" aren't valid, such as TLS symbols and unconverted GOT-based references, so we eliminate those here. */ -bool -mn10300_legitimate_constant_p (rtx x) +static bool +mn10300_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) { switch (GET_CODE (x)) { @@ -2168,7 +2162,8 @@ with an address register. */ static int -mn10300_address_cost (rtx x, bool speed) +mn10300_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED, + addr_space_t as ATTRIBUTE_UNUSED, bool speed) { HOST_WIDE_INT i; rtx base, index; @@ -2221,7 +2216,7 @@ return speed ? 2 : 6; default: - return rtx_cost (x, MEM, speed); + return rtx_cost (x, Pmode, MEM, 0, speed); } } @@ -2232,7 +2227,7 @@ early exit from reload meaning no work is required. */ static int -mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, +mn10300_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, reg_class_t ifrom, reg_class_t ito) { enum reg_class from = (enum reg_class) ifrom; @@ -2319,7 +2314,7 @@ move cost above. This is not a problem. */ static int -mn10300_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, +mn10300_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, reg_class_t iclass, bool in ATTRIBUTE_UNUSED) { enum reg_class rclass = (enum reg_class) iclass; @@ -2335,12 +2330,14 @@ to represent cycles. Size-relative costs are in bytes. */ static bool -mn10300_rtx_costs (rtx x, int code, int outer_code, int *ptotal, bool speed) +mn10300_rtx_costs (rtx x, machine_mode mode, int outer_code, + int opno ATTRIBUTE_UNUSED, int *ptotal, bool speed) { /* This value is used for SYMBOL_REF etc where we want to pretend we have a full 32-bit constant. */ HOST_WIDE_INT i = 0x12345678; int total; + int code = GET_CODE (x); switch (code) { @@ -2426,7 +2423,7 @@ i = INTVAL (XEXP (x, 1)); if (i == 1 || i == 4) { - total = 1 + rtx_cost (XEXP (x, 0), PLUS, speed); + total = 1 + rtx_cost (XEXP (x, 0), mode, PLUS, 0, speed); goto alldone; } } @@ -2482,7 +2479,8 @@ break; case MEM: - total = mn10300_address_cost (XEXP (x, 0), speed); + total = mn10300_address_cost (XEXP (x, 0), mode, + MEM_ADDR_SPACE (x), speed); if (speed) total = COSTS_N_INSNS (2 + total); goto alldone; @@ -2505,12 +2503,15 @@ may access it using GOTOFF instead of GOT. */ static void -mn10300_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) +mn10300_encode_section_info (tree decl, rtx rtl, int first) { rtx symbol; + default_encode_section_info (decl, rtl, first); + if (! MEM_P (rtl)) return; + symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; @@ -2554,7 +2555,7 @@ clobber the flags but do not affect the contents of D0 or D1. */ disp = expand_binop (SImode, sub_optab, fnaddr, - plus_constant (XEXP (m_tramp, 0), 11), + plus_constant (Pmode, XEXP (m_tramp, 0), 11), NULL_RTX, 1, OPTAB_DIRECT); mem = adjust_address (m_tramp, SImode, 0); @@ -2625,14 +2626,19 @@ return true; } -bool -mn10300_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) +/* Implement TARGET_HARD_REGNO_MODE_OK. */ + +static bool +mn10300_hard_regno_mode_ok (unsigned int regno, machine_mode mode) { if (REGNO_REG_CLASS (regno) == FP_REGS || REGNO_REG_CLASS (regno) == FP_ACC_REGS) /* Do not store integer values in FP registers. */ return GET_MODE_CLASS (mode) == MODE_FLOAT && ((regno & 1) == 0); - + + if (! TARGET_AM33 && REGNO_REG_CLASS (regno) == EXTENDED_REGS) + return false; + if (((regno) & 1) == 0 || GET_MODE_SIZE (mode) == 4) return true; @@ -2644,8 +2650,10 @@ return false; } -bool -mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2) +/* Implement TARGET_MODES_TIEABLE_P. */ + +static bool +mn10300_modes_tieable_p (machine_mode mode1, machine_mode mode2) { if (GET_MODE_CLASS (mode1) == MODE_FLOAT && GET_MODE_CLASS (mode2) != MODE_FLOAT) @@ -2664,17 +2672,17 @@ } static int -cc_flags_for_mode (enum machine_mode mode) +cc_flags_for_mode (machine_mode mode) { switch (mode) { - case CCmode: + case E_CCmode: return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C | CC_FLAG_V; - case CCZNCmode: + case E_CCZNCmode: return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C; - case CCZNmode: + case E_CCZNmode: return CC_FLAG_Z | CC_FLAG_N; - case CC_FLOATmode: + case E_CC_FLOATmode: return -1; default: gcc_unreachable (); @@ -2693,7 +2701,6 @@ case LT: /* N */ case GE: /* ~N */ return CC_FLAG_N; - break; case GT: /* ~(Z|(N^V)) */ case LE: /* Z|(N^V) */ @@ -2722,7 +2729,7 @@ } } -enum machine_mode +machine_mode mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED) { int req; @@ -2740,21 +2747,15 @@ } static inline bool -is_load_insn (rtx insn) +set_is_load_p (rtx set) { - if (GET_CODE (PATTERN (insn)) != SET) - return false; - - return MEM_P (SET_SRC (PATTERN (insn))); + return MEM_P (SET_SRC (set)); } static inline bool -is_store_insn (rtx insn) +set_is_store_p (rtx set) { - if (GET_CODE (PATTERN (insn)) != SET) - return false; - - return MEM_P (SET_DEST (PATTERN (insn))); + return MEM_P (SET_DEST (set)); } /* Update scheduling costs for situations that cannot be @@ -2764,42 +2765,46 @@ COST is the current cycle cost for DEP. */ static int -mn10300_adjust_sched_cost (rtx insn, rtx link, rtx dep, int cost) +mn10300_adjust_sched_cost (rtx_insn *insn, int dep_type, rtx_insn *dep, + int cost, unsigned int) { - int timings = get_attr_timings (insn); + rtx insn_set; + rtx dep_set; + int timings; if (!TARGET_AM33) return 1; - if (GET_CODE (insn) == PARALLEL) - insn = XVECEXP (insn, 0, 0); - - if (GET_CODE (dep) == PARALLEL) - dep = XVECEXP (dep, 0, 0); + /* We are only interested in pairs of SET. */ + insn_set = single_set (insn); + if (!insn_set) + return cost; + + dep_set = single_set (dep); + if (!dep_set) + return cost; /* For the AM34 a load instruction that follows a store instruction incurs an extra cycle of delay. */ if (mn10300_tune_cpu == PROCESSOR_AM34 - && is_load_insn (dep) - && is_store_insn (insn)) + && set_is_load_p (dep_set) + && set_is_store_p (insn_set)) cost += 1; /* For the AM34 a non-store, non-branch FPU insn that follows another FPU insn incurs a one cycle throughput increase. */ else if (mn10300_tune_cpu == PROCESSOR_AM34 - && ! is_store_insn (insn) + && ! set_is_store_p (insn_set) && ! JUMP_P (insn) - && GET_CODE (PATTERN (dep)) == SET - && GET_CODE (PATTERN (insn)) == SET - && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) == MODE_FLOAT - && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) == MODE_FLOAT) + && GET_MODE_CLASS (GET_MODE (SET_SRC (dep_set))) == MODE_FLOAT + && GET_MODE_CLASS (GET_MODE (SET_SRC (insn_set))) == MODE_FLOAT) cost += 1; /* Resolve the conflict described in section 1-7-4 of Chapter 3 of the MN103E Series Instruction Manual where it says: - "When the preceeding instruction is a CPU load or + "When the preceding instruction is a CPU load or store instruction, a following FPU instruction cannot be executed until the CPU completes the latency period even though there are no register @@ -2810,27 +2815,25 @@ return cost; /* If a data dependence already exists then the cost is correct. */ - if (REG_NOTE_KIND (link) == 0) + if (dep_type == 0) return cost; /* Check that the instruction about to scheduled is an FPU instruction. */ - if (GET_CODE (PATTERN (dep)) != SET) - return cost; - - if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) != MODE_FLOAT) + if (GET_MODE_CLASS (GET_MODE (SET_SRC (dep_set))) != MODE_FLOAT) return cost; /* Now check to see if the previous instruction is a load or store. */ - if (! is_load_insn (insn) && ! is_store_insn (insn)) + if (! set_is_load_p (insn_set) && ! set_is_store_p (insn_set)) return cost; /* XXX: Verify: The text of 1-7-4 implies that the restriction - only applies when an INTEGER load/store preceeds an FPU + only applies when an INTEGER load/store precedes an FPU instruction, but is this true ? For now we assume that it is. */ - if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) != MODE_INT) + if (GET_MODE_CLASS (GET_MODE (SET_SRC (insn_set))) != MODE_INT) return cost; /* Extract the latency value from the timings attribute. */ + timings = get_attr_timings (insn); return timings < 100 ? (timings % 10) : (timings % 100); } @@ -2856,49 +2859,49 @@ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; } -/* Worker function for TARGET_MD_ASM_CLOBBERS. +/* Worker function for TARGET_MD_ASM_ADJUST. We do this in the mn10300 backend to maintain source compatibility with the old cc0-based compiler. */ -static tree -mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED, - tree inputs ATTRIBUTE_UNUSED, - tree clobbers) +static rtx_insn * +mn10300_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/, + vec<const char *> &/*constraints*/, + vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs) { - clobbers = tree_cons (NULL_TREE, build_string (5, "EPSW"), - clobbers); - return clobbers; + clobbers.safe_push (gen_rtx_REG (CCmode, CC_REG)); + SET_HARD_REG_BIT (clobbered_regs, CC_REG); + return NULL; } /* A helper function for splitting cbranch patterns after reload. */ void -mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref) +mn10300_split_cbranch (machine_mode cmp_mode, rtx cmp_op, rtx label_ref) { rtx flags, x; flags = gen_rtx_REG (cmp_mode, CC_REG); x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1)); - x = gen_rtx_SET (VOIDmode, flags, x); + x = gen_rtx_SET (flags, x); emit_insn (x); x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx); x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx); - x = gen_rtx_SET (VOIDmode, pc_rtx, x); + x = gen_rtx_SET (pc_rtx, x); emit_jump_insn (x); } /* A helper function for matching parallels that set the flags. */ bool -mn10300_match_ccmode (rtx insn, enum machine_mode cc_mode) +mn10300_match_ccmode (rtx insn, machine_mode cc_mode) { rtx op1, flags; - enum machine_mode flags_mode; + machine_mode flags_mode; gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2); - op1 = XVECEXP (PATTERN (insn), 0, 1); + op1 = XVECEXP (PATTERN (insn), 0, 0); gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE); flags = SET_DEST (op1); @@ -2916,6 +2919,23 @@ return true; } +/* This function is used to help split: + + (set (reg) (and (reg) (int))) + + into: + + (set (reg) (shift (reg) (int)) + (set (reg) (shift (reg) (int)) + + where the shitfs will be shorter than the "and" insn. + + It returns the number of bits that should be shifted. A positive + values means that the low bits are to be cleared (and hence the + shifts should be right followed by left) whereas a negative value + means that the high bits are to be cleared (left followed by right). + Zero is returned when it would not be economical to split the AND. */ + int mn10300_split_and_operand_count (rtx op) { @@ -2932,7 +2952,7 @@ would be replacing 1 6-byte insn with 2 3-byte insns. */ if (count > (optimize_insn_for_speed_p () ? 2 : 4)) return 0; - return -count; + return count; } else { @@ -2960,14 +2980,14 @@ cannot be bundled. */ static bool -extract_bundle (rtx insn, struct liw_data * pdata) +extract_bundle (rtx_insn *insn, struct liw_data * pdata) { bool allow_consts = true; - rtx p,s; + rtx p; gcc_assert (pdata != NULL); - if (insn == NULL_RTX) + if (insn == NULL) return false; /* Make sure that we are dealing with a simple SET insn. */ p = single_set (insn); @@ -2981,8 +3001,6 @@ pdata->op = get_attr_liw_op (insn); - s = SET_SRC (p); - switch (pdata->op) { case LIW_OP_MOV: @@ -3088,11 +3106,11 @@ static void mn10300_bundle_liw (void) { - rtx r; - - for (r = get_insns (); r != NULL_RTX; r = next_nonnote_nondebug_insn (r)) + rtx_insn *r; + + for (r = get_insns (); r != NULL; r = next_nonnote_nondebug_insn (r)) { - rtx insn1, insn2; + rtx_insn *insn1, *insn2; struct liw_data liw1, liw2; insn1 = r; @@ -3118,27 +3136,194 @@ delete_insn (insn2); + rtx insn2_pat; if (liw1.op == LIW_OP_CMP) - insn2 = gen_cmp_liw (liw2.dest, liw2.src, liw1.dest, liw1.src, - GEN_INT (liw2.op)); + insn2_pat = gen_cmp_liw (liw2.dest, liw2.src, liw1.dest, liw1.src, + GEN_INT (liw2.op)); else if (liw2.op == LIW_OP_CMP) - insn2 = gen_liw_cmp (liw1.dest, liw1.src, liw2.dest, liw2.src, - GEN_INT (liw1.op)); + insn2_pat = gen_liw_cmp (liw1.dest, liw1.src, liw2.dest, liw2.src, + GEN_INT (liw1.op)); else - insn2 = gen_liw (liw1.dest, liw2.dest, liw1.src, liw2.src, - GEN_INT (liw1.op), GEN_INT (liw2.op)); - - insn2 = emit_insn_after (insn2, insn1); + insn2_pat = gen_liw (liw1.dest, liw2.dest, liw1.src, liw2.src, + GEN_INT (liw1.op), GEN_INT (liw2.op)); + + insn2 = emit_insn_after (insn2_pat, insn1); delete_insn (insn1); r = insn2; } } +#define DUMP(reason, insn) \ + do \ + { \ + if (dump_file) \ + { \ + fprintf (dump_file, reason "\n"); \ + if (insn != NULL_RTX) \ + print_rtl_single (dump_file, insn); \ + fprintf(dump_file, "\n"); \ + } \ + } \ + while (0) + +/* Replace the BRANCH insn with a Lcc insn that goes to LABEL. + Insert a SETLB insn just before LABEL. */ + +static void +mn10300_insert_setlb_lcc (rtx_insn *label, rtx_insn *branch) +{ + rtx lcc, comparison, cmp_reg; + + if (LABEL_NUSES (label) > 1) + { + rtx_insn *insn; + + /* This label is used both as an entry point to the loop + and as a loop-back point for the loop. We need to separate + these two functions so that the SETLB happens upon entry, + but the loop-back does not go to the SETLB instruction. */ + DUMP ("Inserting SETLB insn after:", label); + insn = emit_insn_after (gen_setlb (), label); + label = gen_label_rtx (); + emit_label_after (label, insn); + DUMP ("Created new loop-back label:", label); + } + else + { + DUMP ("Inserting SETLB insn before:", label); + emit_insn_before (gen_setlb (), label); + } + + comparison = XEXP (SET_SRC (PATTERN (branch)), 0); + cmp_reg = XEXP (comparison, 0); + gcc_assert (REG_P (cmp_reg)); + + /* If the comparison has not already been split out of the branch + then do so now. */ + gcc_assert (REGNO (cmp_reg) == CC_REG); + + if (GET_MODE (cmp_reg) == CC_FLOATmode) + lcc = gen_FLcc (comparison, label); + else + lcc = gen_Lcc (comparison, label); + + rtx_insn *jump = emit_jump_insn_before (lcc, branch); + mark_jump_label (XVECEXP (lcc, 0, 0), jump, 0); + JUMP_LABEL (jump) = label; + DUMP ("Replacing branch insn...", branch); + DUMP ("... with Lcc insn:", jump); + delete_insn (branch); +} + +static bool +mn10300_block_contains_call (basic_block block) +{ + rtx_insn *insn; + + FOR_BB_INSNS (block, insn) + if (CALL_P (insn)) + return true; + + return false; +} + +static bool +mn10300_loop_contains_call_insn (loop_p loop) +{ + basic_block * bbs; + bool result = false; + unsigned int i; + + bbs = get_loop_body (loop); + + for (i = 0; i < loop->num_nodes; i++) + if (mn10300_block_contains_call (bbs[i])) + { + result = true; + break; + } + + free (bbs); + return result; +} + +static void +mn10300_scan_for_setlb_lcc (void) +{ + loop_p loop; + + DUMP ("Looking for loops that can use the SETLB insn", NULL_RTX); + + df_analyze (); + compute_bb_for_insn (); + + /* Find the loops. */ + loop_optimizer_init (AVOID_CFG_MODIFICATIONS); + + /* FIXME: For now we only investigate innermost loops. In practice however + if an inner loop is not suitable for use with the SETLB/Lcc insns, it may + be the case that its parent loop is suitable. Thus we should check all + loops, but work from the innermost outwards. */ + FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST) + { + const char * reason = NULL; + + /* Check to see if we can modify this loop. If we cannot + then set 'reason' to describe why it could not be done. */ + if (loop->latch == NULL) + reason = "it contains multiple latches"; + else if (loop->header != loop->latch) + /* FIXME: We could handle loops that span multiple blocks, + but this requires a lot more work tracking down the branches + that need altering, so for now keep things simple. */ + reason = "the loop spans multiple blocks"; + else if (mn10300_loop_contains_call_insn (loop)) + reason = "it contains CALL insns"; + else + { + rtx_insn *branch = BB_END (loop->latch); + + gcc_assert (JUMP_P (branch)); + if (single_set (branch) == NULL_RTX || ! any_condjump_p (branch)) + /* We cannot optimize tablejumps and the like. */ + /* FIXME: We could handle unconditional jumps. */ + reason = "it is not a simple loop"; + else + { + rtx_insn *label; + + if (dump_file) + flow_loop_dump (loop, dump_file, NULL, 0); + + label = BB_HEAD (loop->header); + gcc_assert (LABEL_P (label)); + + mn10300_insert_setlb_lcc (label, branch); + } + } + + if (dump_file && reason != NULL) + fprintf (dump_file, "Loop starting with insn %d is not suitable because %s\n", + INSN_UID (BB_HEAD (loop->header)), + reason); + } + + loop_optimizer_finalize (); + + df_finish_pass (false); + + DUMP ("SETLB scan complete", NULL_RTX); +} + static void mn10300_reorg (void) { - if (TARGET_AM33) + /* These are optimizations, so only run them if optimizing. */ + if (TARGET_AM33 && (optimize > 0 || optimize_size)) { + if (TARGET_ALLOW_SETLB) + mn10300_scan_for_setlb_lcc (); + if (TARGET_ALLOW_LIW) mn10300_bundle_liw (); } @@ -3149,9 +3334,6 @@ #undef TARGET_MACHINE_DEPENDENT_REORG #define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg -#undef TARGET_EXCEPT_UNWIND_INFO -#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info - #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" @@ -3175,14 +3357,8 @@ #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra -#undef TARGET_DEFAULT_TARGET_FLAGS -#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW -#undef TARGET_HANDLE_OPTION -#define TARGET_HANDLE_OPTION mn10300_handle_option #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE mn10300_option_override -#undef TARGET_OPTION_OPTIMIZATION_TABLE -#define TARGET_OPTION_OPTIMIZATION_TABLE mn10300_option_optimization_table #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info @@ -3210,10 +3386,15 @@ #undef TARGET_CASE_VALUES_THRESHOLD #define TARGET_CASE_VALUES_THRESHOLD mn10300_case_values_threshold +#undef TARGET_LRA_P +#define TARGET_LRA_P hook_bool_void_false + #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P mn10300_legitimate_address_p #undef TARGET_DELEGITIMIZE_ADDRESS #define TARGET_DELEGITIMIZE_ADDRESS mn10300_delegitimize_address +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P mn10300_legitimate_constant_p #undef TARGET_PREFERRED_RELOAD_CLASS #define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class @@ -3242,10 +3423,16 @@ #undef TARGET_CONDITIONAL_REGISTER_USAGE #define TARGET_CONDITIONAL_REGISTER_USAGE mn10300_conditional_register_usage -#undef TARGET_MD_ASM_CLOBBERS -#define TARGET_MD_ASM_CLOBBERS mn10300_md_asm_clobbers +#undef TARGET_MD_ASM_ADJUST +#define TARGET_MD_ASM_ADJUST mn10300_md_asm_adjust #undef TARGET_FLAGS_REGNUM #define TARGET_FLAGS_REGNUM CC_REG +#undef TARGET_HARD_REGNO_MODE_OK +#define TARGET_HARD_REGNO_MODE_OK mn10300_hard_regno_mode_ok + +#undef TARGET_MODES_TIEABLE_P +#define TARGET_MODES_TIEABLE_P mn10300_modes_tieable_p + struct gcc_target targetm = TARGET_INITIALIZER;