diff options
Diffstat (limited to 'gcc/config/msp430')
-rw-r--r-- | gcc/config/msp430/constraints.md | 4 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-c.c | 11 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-modes.def | 1 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-opts.h | 32 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-protos.h | 16 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.c | 673 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.h | 23 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.md | 192 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.opt | 35 | ||||
-rw-r--r-- | gcc/config/msp430/predicates.md | 6 | ||||
-rw-r--r-- | gcc/config/msp430/t-msp430 | 2 |
11 files changed, 818 insertions, 177 deletions
diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md index 055125f5b1c..c3c0a54233d 100644 --- a/gcc/config/msp430/constraints.md +++ b/gcc/config/msp430/constraints.md @@ -1,5 +1,5 @@ ;; Machine Description for TI MSP43* processors -;; Copyright (C) 2013-2014 Free Software Foundation, Inc. +;; Copyright (C) 2013-2015 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; This file is part of GCC. @@ -58,7 +58,7 @@ (match_code "label_ref" "0"))) -;; These are memory references that are safe to use with the X suffix, +;; These are memory references that are safe to use without the X suffix, ;; because we know/assume they need not index across the 64k boundary. (define_constraint "Ys" "Memory reference, stack only." diff --git a/gcc/config/msp430/msp430-c.c b/gcc/config/msp430/msp430-c.c index b637192a0a2..036050c2c7c 100644 --- a/gcc/config/msp430/msp430-c.c +++ b/gcc/config/msp430/msp430-c.c @@ -1,5 +1,5 @@ /* MSP430 C-specific support - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. Contributed by Red Hat, Inc. This file is part of GCC. @@ -22,6 +22,15 @@ #include "system.h" #include "coretypes.h" #include "tm.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" #include "c-family/c-common.h" #include "msp430-protos.h" diff --git a/gcc/config/msp430/msp430-modes.def b/gcc/config/msp430/msp430-modes.def index 4e94a6df597..d170e48eb64 100644 --- a/gcc/config/msp430/msp430-modes.def +++ b/gcc/config/msp430/msp430-modes.def @@ -1,3 +1,4 @@ /* 20-bit address */ PARTIAL_INT_MODE (SI, 20, PSI); +INT_N (PSI, 20); diff --git a/gcc/config/msp430/msp430-opts.h b/gcc/config/msp430/msp430-opts.h new file mode 100644 index 00000000000..ad3ca6d5d2c --- /dev/null +++ b/gcc/config/msp430/msp430-opts.h @@ -0,0 +1,32 @@ +/* GCC option-handling definitions for the TI MSP430 + Copyright (C) 2014-2015 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef MSP430_OPTS_H +#define MSP430_OPTS_H + +enum msp430_hwmult_types +{ + NONE, + AUTO, + SMALL, + LARGE, + F5SERIES +}; + +#endif diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index 7f999abbdab..6246a64a5dc 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -1,5 +1,5 @@ /* Exported function prototypes from the TI MSP430 backend. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -27,23 +27,25 @@ void msp430_expand_epilogue (int); void msp430_expand_helper (rtx *operands, const char *, bool); void msp430_expand_prologue (void); const char * msp430x_extendhisi (rtx *); -void msp430_fixup_compare_operands (enum machine_mode, rtx *); -int msp430_hard_regno_mode_ok (int, enum machine_mode); -int msp430_hard_regno_nregs (int, enum machine_mode); +void msp430_fixup_compare_operands (machine_mode, rtx *); +int msp430_hard_regno_mode_ok (int, machine_mode); +int msp430_hard_regno_nregs (int, machine_mode); +int msp430_hard_regno_nregs_has_padding (int, machine_mode); +int msp430_hard_regno_nregs_with_padding (int, machine_mode); bool msp430_hwmult_enabled (void); rtx msp430_incoming_return_addr_rtx (void); void msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); int msp430_initial_elimination_offset (int, int); -bool msp430_is_f5_mcu (void); bool msp430_is_interrupt_func (void); const char * msp430x_logical_shift_right (rtx); const char * msp430_mcu_name (void); -bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode); +bool msp430_modes_tieable_p (machine_mode, machine_mode); void msp430_output_labelref (FILE *, const char *); void msp430_register_pragmas (void); rtx msp430_return_addr_rtx (int); void msp430_split_movsi (rtx *); void msp430_start_function (FILE *, const char *, tree); -rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int); +rtx msp430_subreg (machine_mode, rtx, machine_mode, int); +bool msp430_use_f5_series_hwmult (void); #endif /* GCC_MSP430_PROTOS_H */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 80a17a6e31e..35d2a7dfe4b 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1,5 +1,5 @@ /* Subroutines used for code generation on TI MSP430 processors. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -22,7 +22,17 @@ #include "system.h" #include "coretypes.h" #include "tm.h" +#include "hash-set.h" +#include "machmode.h" +#include "vec.h" +#include "double-int.h" +#include "input.h" +#include "alias.h" +#include "symtab.h" +#include "wide-int.h" +#include "inchash.h" #include "tree.h" +#include "fold-const.h" #include "stor-layout.h" #include "calls.h" #include "rtl.h" @@ -34,13 +44,33 @@ #include "insn-attr.h" #include "flags.h" #include "function.h" +#include "hashtab.h" +#include "statistics.h" +#include "real.h" +#include "fixed-value.h" +#include "expmed.h" +#include "dojump.h" +#include "explow.h" +#include "emit-rtl.h" +#include "varasm.h" +#include "stmt.h" #include "expr.h" +#include "insn-codes.h" #include "optabs.h" #include "libfuncs.h" #include "recog.h" #include "diagnostic-core.h" #include "toplev.h" #include "reload.h" +#include "dominance.h" +#include "cfg.h" +#include "cfgrtl.h" +#include "cfganal.h" +#include "lcm.h" +#include "cfgbuild.h" +#include "cfgcleanup.h" +#include "predict.h" +#include "basic-block.h" #include "df.h" #include "ggc.h" #include "tm_p.h" @@ -51,6 +81,7 @@ #include "msp430-protos.h" #include "dumpfile.h" #include "opts.h" +#include "builtins.h" static void msp430_compute_frame_info (void); @@ -90,23 +121,11 @@ msp430_init_machine_status (void) { struct machine_function *m; - m = ggc_alloc_cleared_machine_function (); + m = ggc_cleared_alloc<machine_function> (); return m; } -#undef TARGET_HANDLE_OPTION -#define TARGET_HANDLE_OPTION msp430_handle_option - -bool -msp430_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED, - struct gcc_options *opts_set ATTRIBUTE_UNUSED, - const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED, - location_t loc ATTRIBUTE_UNUSED) -{ - return true; -} - #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE msp430_option_override @@ -196,19 +215,14 @@ msp430_option_override (void) if (target_cpu) { - if (strcasecmp (target_cpu, "msp430x") == 0 - || strcasecmp (target_cpu, "msp430xv2") == 0 - || strcasecmp (target_cpu, "430x") == 0 - || strcasecmp (target_cpu, "430xv2") == 0) + if (strcasecmp (target_cpu, "msp430x") == 0) msp430x = true; - else if (strcasecmp (target_cpu, "msp430") == 0 - || strcasecmp (target_cpu, "430") == 0) + else /* target_cpu == "msp430" - already handled by the front end. */ msp430x = false; - else - error ("unrecognised argument of -mcpu: %s", target_cpu); } - - if (target_mcu) + /* Note - the front end has already ensured at most + one of target_cpu and target_mcu will be set. */ + else if (target_mcu) { int i; @@ -217,25 +231,12 @@ msp430_option_override (void) supports 430. */ msp430x = true; - /* For backwards compatibility we recognise two generic MCU - 430X names. However we want to be able to generate special C - preprocessor defines for them, which is why we set target_mcu - to NULL. */ - if (strcasecmp (target_mcu, "msp430") == 0) - { - msp430x = false; - target_mcu = NULL; - } - else if (strcasecmp (target_mcu, "msp430x") == 0 - || strcasecmp (target_mcu, "msp430xv2") == 0) - target_mcu = NULL; - else - for (i = ARRAY_SIZE (msp430_mcu_names); i--;) - if (strcasecmp (msp430_mcu_names[i], target_mcu) == 0) - { - msp430x = false; - break; - } + for (i = ARRAY_SIZE (msp430_mcu_names); i--;) + if (strcasecmp (msp430_mcu_names[i], target_mcu) == 0) + { + msp430x = false; + break; + } /* It is not an error if we do not match the MCU name. There are hundreds of them. */ } @@ -257,6 +258,21 @@ msp430_option_override (void) optimize_size = 1; } +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p + +static bool +msp430_scalar_mode_supported_p (machine_mode m) +{ + if (m == PSImode && msp430x) + return true; +#if 0 + if (m == TImode) + return true; +#endif + return default_scalar_mode_supported_p (m); +} + /* Storage Layout */ @@ -278,7 +294,7 @@ msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED) PSImode value, but not an SImode value. */ int msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED, - enum machine_mode mode) + machine_mode mode) { if (mode == PSImode && msp430x) return 1; @@ -286,17 +302,38 @@ msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED, / UNITS_PER_WORD); } +/* Implements HARD_REGNO_NREGS_HAS_PADDING. */ +int +msp430_hard_regno_nregs_has_padding (int regno ATTRIBUTE_UNUSED, + machine_mode mode) +{ + if (mode == PSImode && msp430x) + return 1; + return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) + / UNITS_PER_WORD); +} + +/* Implements HARD_REGNO_NREGS_WITH_PADDING. */ +int +msp430_hard_regno_nregs_with_padding (int regno ATTRIBUTE_UNUSED, + machine_mode mode) +{ + if (mode == PSImode) + return 2; + return msp430_hard_regno_nregs (regno, mode); +} + /* Implements HARD_REGNO_MODE_OK. */ int msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED, - enum machine_mode mode) + machine_mode mode) { return regno <= (ARG_POINTER_REGNUM - msp430_hard_regno_nregs (regno, mode)); } /* Implements MODES_TIEABLE_P. */ bool -msp430_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2) +msp430_modes_tieable_p (machine_mode mode1, machine_mode mode2) { if ((mode1 == PSImode || mode2 == SImode) || (mode1 == SImode || mode2 == PSImode)) @@ -376,7 +413,7 @@ msp430_initial_elimination_offset (int from, int to) #undef TARGET_ADDR_SPACE_ADDRESS_MODE #define TARGET_ADDR_SPACE_ADDRESS_MODE msp430_addr_space_pointer_mode -static enum machine_mode +static machine_mode msp430_addr_space_pointer_mode (addr_space_t addrspace) { switch (addrspace) @@ -396,10 +433,10 @@ msp430_addr_space_pointer_mode (addr_space_t addrspace) #undef TARGET_UNWIND_WORD_MODE #define TARGET_UNWIND_WORD_MODE msp430_unwind_word_mode -static enum machine_mode +static machine_mode msp430_unwind_word_mode (void) { - return TARGET_LARGE ? SImode : HImode; + return TARGET_LARGE ? PSImode : HImode; } /* Determine if one named address space is a subset of another. */ @@ -512,7 +549,7 @@ msp430_function_value (const_tree ret_type, #define TARGET_LIBCALL_VALUE msp430_libcall_value rtx -msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +msp430_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) { return gen_rtx_REG (mode, 12); } @@ -545,7 +582,7 @@ msp430_init_cumulative_args (CUMULATIVE_ARGS *ca, code that determines where an argument will be passed. */ static void msp430_evaluate_arg (cumulative_args_t cap, - enum machine_mode mode, + machine_mode mode, const_tree type ATTRIBUTE_UNUSED, bool named) { @@ -630,7 +667,7 @@ msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED) rtx msp430_function_arg (cumulative_args_t cap, - enum machine_mode mode, + machine_mode mode, const_tree type, bool named) { @@ -649,7 +686,7 @@ msp430_function_arg (cumulative_args_t cap, int msp430_arg_partial_bytes (cumulative_args_t cap, - enum machine_mode mode, + machine_mode mode, tree type, bool named) { @@ -668,7 +705,7 @@ msp430_arg_partial_bytes (cumulative_args_t cap, static bool msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED, - enum machine_mode mode, + machine_mode mode, const_tree type, bool named ATTRIBUTE_UNUSED) { @@ -682,7 +719,7 @@ msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED, static bool msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, const_tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED) { @@ -694,7 +731,7 @@ msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED, void msp430_function_arg_advance (cumulative_args_t cap, - enum machine_mode mode, + machine_mode mode, const_tree type, bool named) { @@ -714,7 +751,7 @@ msp430_function_arg_advance (cumulative_args_t cap, #define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary static unsigned int -msp430_function_arg_boundary (enum machine_mode mode, const_tree type) +msp430_function_arg_boundary (machine_mode mode, const_tree type) { if (mode == BLKmode && int_size_in_bytes (type) > 1) @@ -730,7 +767,7 @@ msp430_function_arg_boundary (enum machine_mode mode, const_tree type) static bool msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED) { - enum machine_mode mode = TYPE_MODE (ret_type); + machine_mode mode = TYPE_MODE (ret_type); if (mode == BLKmode || (fntype && TREE_CODE (TREE_TYPE (fntype)) == RECORD_TYPE) @@ -746,7 +783,7 @@ msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED #undef TARGET_GET_RAW_ARG_MODE #define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode -static enum machine_mode +static machine_mode msp430_get_raw_arg_mode (int regno) { return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode; @@ -755,11 +792,102 @@ msp430_get_raw_arg_mode (int regno) #undef TARGET_GET_RAW_RESULT_MODE #define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode -static enum machine_mode +static machine_mode msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED) { return Pmode; } + +#undef TARGET_GIMPLIFY_VA_ARG_EXPR +#define TARGET_GIMPLIFY_VA_ARG_EXPR msp430_gimplify_va_arg_expr + +#include "gimplify.h" +#include "gimple-expr.h" + +static tree +msp430_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, + gimple_seq *post_p) +{ + tree addr, t, type_size, rounded_size, valist_tmp; + unsigned HOST_WIDE_INT align, boundary; + bool indirect; + + indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); + if (indirect) + type = build_pointer_type (type); + + align = PARM_BOUNDARY / BITS_PER_UNIT; + boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type); + + /* When we align parameter on stack for caller, if the parameter + alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be + aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee + here with caller. */ + if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT) + boundary = MAX_SUPPORTED_STACK_ALIGNMENT; + + boundary /= BITS_PER_UNIT; + + /* Hoist the valist value into a temporary for the moment. */ + valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL); + + /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually + requires greater alignment, we must perform dynamic alignment. */ + if (boundary > align + && !integer_zerop (TYPE_SIZE (type))) + { + /* FIXME: This is where this function diverts from targhooks.c: + std_gimplify_va_arg_expr(). It works, but I do not know why... */ + if (! POINTER_TYPE_P (type)) + { + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, + fold_build_pointer_plus_hwi (valist_tmp, boundary - 1)); + gimplify_and_add (t, pre_p); + + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, + fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist), + valist_tmp, + build_int_cst (TREE_TYPE (valist), -boundary))); + gimplify_and_add (t, pre_p); + } + } + else + boundary = align; + + /* If the actual alignment is less than the alignment of the type, + adjust the type accordingly so that we don't assume strict alignment + when dereferencing the pointer. */ + boundary *= BITS_PER_UNIT; + if (boundary < TYPE_ALIGN (type)) + { + type = build_variant_type_copy (type); + TYPE_ALIGN (type) = boundary; + } + + /* Compute the rounded size of the type. */ + type_size = size_in_bytes (type); + rounded_size = round_up (type_size, align); + + /* Reduce rounded_size so it's sharable with the postqueue. */ + gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue); + + /* Get AP. */ + addr = valist_tmp; + + /* Compute new value for AP. */ + t = fold_build_pointer_plus (valist_tmp, rounded_size); + t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); + gimplify_and_add (t, pre_p); + + addr = fold_convert (build_pointer_type (type), addr); + + if (indirect) + addr = build_va_arg_indirect_ref (addr); + + addr = build_va_arg_indirect_ref (addr); + + return addr; +} /* Addressing Modes */ @@ -781,7 +909,7 @@ reg_ok_for_addr (rtx r, bool strict) } bool -msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, +msp430_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, bool strict ATTRIBUTE_UNUSED) { @@ -823,11 +951,57 @@ msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, } } +#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P msp430_addr_space_legitimate_address_p + +bool +msp430_addr_space_legitimate_address_p (machine_mode mode, + rtx x, + bool strict, + addr_space_t as ATTRIBUTE_UNUSED) +{ + return msp430_legitimate_address_p (mode, x, strict); +} + +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER msp430_asm_integer +static bool +msp430_asm_integer (rtx x, unsigned int size, int aligned_p) +{ + int c = GET_CODE (x); + + if (size == 3 && GET_MODE (x) == PSImode) + size = 4; + + switch (size) + { + case 4: + if (c == SYMBOL_REF || c == CONST || c == LABEL_REF || c == CONST_INT) + { + fprintf (asm_out_file, "\t.long\t"); + output_addr_const (asm_out_file, x); + fputc ('\n', asm_out_file); + return true; + } + break; + } + return default_assemble_integer (x, size, aligned_p); +} + +#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA +#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA msp430_asm_output_addr_const_extra +static bool +msp430_asm_output_addr_const_extra (FILE *file ATTRIBUTE_UNUSED, rtx x) +{ + debug_rtx(x); + return false; +} + #undef TARGET_LEGITIMATE_CONSTANT_P #define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant static bool -msp430_legitimate_constant (enum machine_mode mode, rtx x) +msp430_legitimate_constant (machine_mode mode, rtx x) { return ! CONST_INT_P (x) || mode != PSImode @@ -1115,7 +1289,7 @@ msp430_attr (tree * node, break; case INTEGER_CST: - if (TREE_INT_CST_LOW (value) > 63) + if (wi::gtu_p (value, 63)) /* Allow the attribute to be added - the linker script being used may still recognise this value. */ warning (OPT_Wattributes, @@ -1224,6 +1398,7 @@ enum msp430_builtin { MSP430_BUILTIN_BIC_SR, MSP430_BUILTIN_BIS_SR, + MSP430_BUILTIN_DELAY_CYCLES, MSP430_BUILTIN_max }; @@ -1233,6 +1408,7 @@ static void msp430_init_builtins (void) { tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL); + tree void_ftype_longlong = build_function_type_list (void_type_node, long_long_integer_type_node, NULL); msp430_builtins[MSP430_BUILTIN_BIC_SR] = add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int, @@ -1241,6 +1417,10 @@ msp430_init_builtins (void) msp430_builtins[MSP430_BUILTIN_BIS_SR] = add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int, MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE); + + msp430_builtins[MSP430_BUILTIN_DELAY_CYCLES] = + add_builtin_function ( "__delay_cycles", void_ftype_longlong, + MSP430_BUILTIN_DELAY_CYCLES, BUILT_IN_MD, NULL, NULL_TREE); } static tree @@ -1250,23 +1430,140 @@ msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED) { case MSP430_BUILTIN_BIC_SR: case MSP430_BUILTIN_BIS_SR: + case MSP430_BUILTIN_DELAY_CYCLES: return msp430_builtins[code]; default: return error_mark_node; } } +/* These constants are really register reads, which are faster than + regular constants. */ +static int +cg_magic_constant (HOST_WIDE_INT c) +{ + switch (c) + { + case 0xffff: + case -1: + case 0: + case 1: + case 2: + case 4: + case 8: + return 1; + default: + return 0; + } +} + +static rtx +msp430_expand_delay_cycles (rtx arg) +{ + HOST_WIDE_INT i, c, n; + /* extra cycles for MSP430X instructions */ +#define CYCX(M,X) (msp430x ? (X) : (M)) + + if (GET_CODE (arg) != CONST_INT) + { + error ("__delay_cycles() only takes constant arguments"); + return NULL_RTX; + } + + c = INTVAL (arg); + + if (HOST_BITS_PER_WIDE_INT > 32) + { + if (c < 0) + { + error ("__delay_cycles only takes non-negative cycle counts."); + return NULL_RTX; + } + } + + emit_insn (gen_delay_cycles_start (arg)); + + /* For 32-bit loops, there's 13(16) + 5(min(x,0x10000) + 6x cycles. */ + if (c > 3 * 0xffff + CYCX (7, 10)) + { + n = c; + /* There's 4 cycles in the short (i>0xffff) loop and 7 in the long (x<=0xffff) loop */ + if (c >= 0x10000 * 7 + CYCX (14, 16)) + { + i = 0x10000; + c -= CYCX (14, 16) + 7 * 0x10000; + i += c / 4; + c %= 4; + if ((unsigned long long) i > 0xffffffffULL) + { + error ("__delay_cycles is limited to 32-bit loop counts."); + return NULL_RTX; + } + } + else + { + i = (c - CYCX (14, 16)) / 7; + c -= CYCX (14, 16) + i * 7; + } + + if (cg_magic_constant (i & 0xffff)) + c ++; + if (cg_magic_constant ((i >> 16) & 0xffff)) + c ++; + + if (msp430x) + emit_insn (gen_delay_cycles_32x (GEN_INT (i), GEN_INT (n - c))); + else + emit_insn (gen_delay_cycles_32 (GEN_INT (i), GEN_INT (n - c))); + } + + /* For 16-bit loops, there's 7(10) + 3x cycles - so the max cycles is 0x30004(7). */ + if (c > 12) + { + n = c; + i = (c - CYCX (7, 10)) / 3; + c -= CYCX (7, 10) + i * 3; + + if (cg_magic_constant (i)) + c ++; + + if (msp430x) + emit_insn (gen_delay_cycles_16x (GEN_INT (i), GEN_INT (n - c))); + else + emit_insn (gen_delay_cycles_16 (GEN_INT (i), GEN_INT (n - c))); + } + + while (c > 1) + { + emit_insn (gen_delay_cycles_2 ()); + c -= 2; + } + + if (c) + { + emit_insn (gen_delay_cycles_1 ()); + c -= 1; + } + + emit_insn (gen_delay_cycles_end (arg)); + + return NULL_RTX; +} + static rtx msp430_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); unsigned int fcode = DECL_FUNCTION_CODE (fndecl); rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + if (fcode == MSP430_BUILTIN_DELAY_CYCLES) + return msp430_expand_delay_cycles (arg1); + if (! msp430_is_interrupt_func ()) { error ("MSP430 builtin functions only work inside interrupt handlers"); @@ -1309,7 +1606,12 @@ msp430_expand_prologue (void) rtx p; if (is_naked_func ()) - return; + { + /* We must generate some RTX as thread_prologue_and_epilogue_insns() + examines the output of the gen_prologue() function. */ + emit_insn (gen_rtx_CLOBBER (VOIDmode, GEN_INT (0))); + return; + } emit_insn (gen_prologue_start_marker ()); @@ -1418,7 +1720,12 @@ msp430_expand_epilogue (int is_eh) int helper_n = 0; if (is_naked_func ()) - return; + { + /* We must generate some RTX as thread_prologue_and_epilogue_insns() + examines the output of the gen_epilogue() function. */ + emit_insn (gen_rtx_CLOBBER (VOIDmode, GEN_INT (0))); + return; + } if (cfun->machine->need_to_save [10]) { @@ -1558,6 +1865,33 @@ msp430_expand_eh_return (rtx eh_handler) emit_move_insn (tmp, ra); } +#undef TARGET_INIT_DWARF_REG_SIZES_EXTRA +#define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra +void +msp430_init_dwarf_reg_sizes_extra (tree address) +{ + int i; + rtx addr = expand_normal (address); + rtx mem = gen_rtx_MEM (BLKmode, addr); + + if (!msp430x) + return; + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + unsigned int dnum = DWARF_FRAME_REGNUM (i); + unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1); + + if (rnum < DWARF_FRAME_REGISTERS) + { + HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (QImode); + + emit_move_insn (adjust_address (mem, QImode, offset), + gen_int_mode (4, QImode)); + } + } +} + /* This is a list of MD patterns that implement fixed-count shifts. */ static struct { @@ -1595,9 +1929,9 @@ msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variant char *helper_const = NULL; int arg2 = 13; int arg1sz = 1; - enum machine_mode arg0mode = GET_MODE (operands[0]); - enum machine_mode arg1mode = GET_MODE (operands[1]); - enum machine_mode arg2mode = GET_MODE (operands[2]); + machine_mode arg0mode = GET_MODE (operands[0]); + machine_mode arg1mode = GET_MODE (operands[1]); + machine_mode arg2mode = GET_MODE (operands[2]); int have_430x = msp430x ? 1 : 0; if (CONST_INT_P (operands[2])) @@ -1662,7 +1996,7 @@ msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variant /* Called by cbranch<mode>4 to coerce operands into usable forms. */ void -msp430_fixup_compare_operands (enum machine_mode my_mode, rtx * operands) +msp430_fixup_compare_operands (machine_mode my_mode, rtx * operands) { /* constants we're looking for, not constants which are allowed. */ int const_op_idx = 1; @@ -1679,7 +2013,7 @@ msp430_fixup_compare_operands (enum machine_mode my_mode, rtx * operands) need it to below, so we use this function for when we must get a valid subreg in a "natural" state. */ rtx -msp430_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte) +msp430_subreg (machine_mode mode, rtx r, machine_mode omode, int byte) { rtx rv; @@ -1687,7 +2021,7 @@ msp430_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte) && SUBREG_BYTE (r) == 0) { rtx ireg = SUBREG_REG (r); - enum machine_mode imode = GET_MODE (ireg); + machine_mode imode = GET_MODE (ireg); /* special case for (HI (SI (PSI ...), 0)) */ if (imode == PSImode @@ -1845,18 +2179,52 @@ static const struct { NULL, NULL } }; -/* Returns true if the current MCU is an F5xxx series. */ +/* Returns true if the current MCU supports an F5xxx series + hardware multiper. */ + bool -msp430_is_f5_mcu (void) +msp430_use_f5_series_hwmult (void) { - if (target_mcu == NULL) + static const char * cached_match = NULL; + static bool cached_result; + + if (msp430_hwmult_type == F5SERIES) + return true; + + if (target_mcu == NULL || msp430_hwmult_type != AUTO) return false; - return strncasecmp (target_mcu, "msp430f5", 8) == 0; + + if (target_mcu == cached_match) + return cached_result; + + cached_match = target_mcu; + + if (strncasecmp (target_mcu, "msp430f5", 8) == 0) + return cached_result = true; + + static const char * known_f5_mult_mcus [] = + { + "cc430f5123", "cc430f5125", "cc430f5133", + "cc430f5135", "cc430f5137", "cc430f5143", + "cc430f5145", "cc430f5147", "cc430f6125", + "cc430f6126", "cc430f6127", "cc430f6135", + "cc430f6137", "cc430f6143", "cc430f6145", + "cc430f6147", "msp430bt5190", "msp430sl5438a" + }; + int i; + + for (i = ARRAY_SIZE (known_f5_mult_mcus); i--;) + if (strcasecmp (target_mcu, known_f5_mult_mcus[i]) == 0) + return cached_result = true; + + return cached_result = false; } -/* Returns true id the current MCU has a second generation 32-bit hardware multiplier. */ +/* Returns true if the current MCU has a second generation + 32-bit hardware multiplier. */ + static bool -has_32bit_hw_mult (void) +use_32bit_hwmult (void) { static const char * known_32bit_mult_mcus [] = { @@ -1867,38 +2235,115 @@ has_32bit_hw_mult (void) "msp430f47186", "msp430f47196", "msp430f47167", "msp430f47177", "msp430f47187", "msp430f47197" }; + static const char * cached_match = NULL; + static bool cached_result; int i; - if (target_mcu == NULL) + + if (msp430_hwmult_type == LARGE) + return true; + + if (target_mcu == NULL || msp430_hwmult_type != AUTO) return false; + if (target_mcu == cached_match) + return cached_result; + + cached_match = target_mcu; for (i = ARRAY_SIZE (known_32bit_mult_mcus); i--;) if (strcasecmp (target_mcu, known_32bit_mult_mcus[i]) == 0) - return true; + return cached_result = true; - return false; + return cached_result = false; } -/* Returns true if hardware multiply is supported by the chosen MCU. */ -bool -msp430_hwmult_enabled (void) +/* Returns true if the current MCU does not have a + hardware multiplier of any kind. */ + +static bool +msp430_no_hwmult (void) { - if (target_mcu == NULL) - return false; + static const char * known_nomult_mcus [] = + { + "msp430c091", "msp430c092", "msp430c111", + "msp430c1111", "msp430c112", "msp430c1121", + "msp430c1331", "msp430c1351", "msp430c311s", + "msp430c312", "msp430c313", "msp430c314", + "msp430c315", "msp430c323", "msp430c325", + "msp430c412", "msp430c413", "msp430e112", + "msp430e313", "msp430e315", "msp430e325", + "msp430f110", "msp430f1101", "msp430f1101a", + "msp430f1111", "msp430f1111a", "msp430f112", + "msp430f1121", "msp430f1121a", "msp430f1122", + "msp430f1132", "msp430f122", "msp430f1222", + "msp430f123", "msp430f1232", "msp430f133", + "msp430f135", "msp430f155", "msp430f156", + "msp430f157", "msp430f2001", "msp430f2002", + "msp430f2003", "msp430f2011", "msp430f2012", + "msp430f2013", "msp430f2101", "msp430f2111", + "msp430f2112", "msp430f2121", "msp430f2122", + "msp430f2131", "msp430f2132", "msp430f2232", + "msp430f2234", "msp430f2252", "msp430f2254", + "msp430f2272", "msp430f2274", "msp430f412", + "msp430f413", "msp430f4132", "msp430f415", + "msp430f4152", "msp430f417", "msp430f4250", + "msp430f4260", "msp430f4270", "msp430f435", + "msp430f4351", "msp430f436", "msp430f4361", + "msp430f437", "msp430f4371", "msp430f438", + "msp430f439", "msp430f477", "msp430f478", + "msp430f479", "msp430fe423", "msp430fe4232", + "msp430fe423a", "msp430fe4242", "msp430fe425", + "msp430fe4252", "msp430fe425a", "msp430fe427", + "msp430fe4272", "msp430fe427a", "msp430fg4250", + "msp430fg4260", "msp430fg4270", "msp430fg437", + "msp430fg438", "msp430fg439", "msp430fg477", + "msp430fg478", "msp430fg479", "msp430fr2032", + "msp430fr2033", "msp430fr4131", "msp430fr4132", + "msp430fr4133", "msp430fw423", "msp430fw425", + "msp430fw427", "msp430fw428", "msp430fw429", + "msp430g2001", "msp430g2101", "msp430g2102", + "msp430g2111", "msp430g2112", "msp430g2113", + "msp430g2121", "msp430g2131", "msp430g2132", + "msp430g2152", "msp430g2153", "msp430g2201", + "msp430g2202", "msp430g2203", "msp430g2210", + "msp430g2211", "msp430g2212", "msp430g2213", + "msp430g2221", "msp430g2230", "msp430g2231", + "msp430g2232", "msp430g2233", "msp430g2252", + "msp430g2253", "msp430g2302", "msp430g2303", + "msp430g2312", "msp430g2313", "msp430g2332", + "msp430g2333", "msp430g2352", "msp430g2353", + "msp430g2402", "msp430g2403", "msp430g2412", + "msp430g2413", "msp430g2432", "msp430g2433", + "msp430g2444", "msp430g2452", "msp430g2453", + "msp430g2513", "msp430g2533", "msp430g2544", + "msp430g2553", "msp430g2744", "msp430g2755", + "msp430g2855", "msp430g2955", "msp430l092", + "msp430p112", "msp430p313", "msp430p315", + "msp430p315s", "msp430p325", "msp430tch5e" + }; + static const char * cached_match = NULL; + static bool cached_result; + int i; - if (!ENABLE_HWMULT) - return false; + if (msp430_hwmult_type == NONE) + return true; - if (msp430_is_interrupt_func ()) + if (target_mcu == NULL || msp430_hwmult_type != AUTO) return false; - if (msp430_is_f5_mcu () || has_32bit_hw_mult ()) - return true; + if (target_mcu == cached_match) + return cached_result; - return false; + cached_match = target_mcu; + for (i = ARRAY_SIZE (known_nomult_mcus); i--;) + if (strcasecmp (target_mcu, known_nomult_mcus[i]) == 0) + return cached_result = true; + + return cached_result = false; } /* This function does the same as the default, but it will replace GCC function names with the MSPABI-specified ones. */ + void msp430_output_labelref (FILE *file, const char *name) { @@ -1913,22 +2358,22 @@ msp430_output_labelref (FILE *file, const char *name) /* If we have been given a specific MCU name then we may be able to make use of its hardware multiply capabilities. */ - if (msp430_hwmult_enabled ()) + if (msp430_hwmult_type != NONE) { if (strcmp ("__mspabi_mpyi", name) == 0) { - if (msp430_is_f5_mcu ()) + if (msp430_use_f5_series_hwmult ()) name = "__mulhi2_f5"; - else + else if (! msp430_no_hwmult ()) name = "__mulhi2"; } else if (strcmp ("__mspabi_mpyl", name) == 0) { - if (msp430_is_f5_mcu ()) + if (msp430_use_f5_series_hwmult ()) name = "__mulsi2_f5"; - else if (has_32bit_hw_mult ()) + else if (use_32bit_hwmult ()) name = "__mulsi2_hw32"; - else + else if (! msp430_no_hwmult ()) name = "__mulsi2"; } } @@ -2179,7 +2624,7 @@ msp430_print_operand (FILE * file, rtx op, int letter) case 'X': /* This is used to turn, for example, an ADD opcode into an ADDX opcode when we're using 20-bit addresses. */ - if (TARGET_LARGE) + if (TARGET_LARGE || GET_MODE (op) == PSImode) fprintf (file, "X"); /* We don't care which operand we use, but we want 'X' in the MD file, so we do it this way. */ @@ -2187,7 +2632,7 @@ msp430_print_operand (FILE * file, rtx op, int letter) case 'x': /* Similarly, but only for PSImodes. BIC, for example, needs this. */ - if (TARGET_LARGE && GET_MODE (op) == PSImode) + if (GET_MODE (op) == PSImode) fprintf (file, "X"); return; @@ -2203,7 +2648,7 @@ msp430_print_operand (FILE * file, rtx op, int letter) because builtins are expanded before the frame layout is determined. */ fprintf (file, "%d", msp430_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM) - - 2); + - (TARGET_LARGE ? 4 : 2)); return; case 'J': @@ -2226,8 +2671,32 @@ msp430_print_operand (FILE * file, rtx op, int letter) msp430_print_operand_addr (file, addr); break; - case CONST_INT: case CONST: + if (GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT) + { + op = XEXP (op, 0); + switch (INTVAL (XEXP (op, 2))) + { + case 0: + fprintf (file, "#lo ("); + msp430_print_operand_raw (file, XEXP (op, 0)); + fprintf (file, ")"); + break; + + case 16: + fprintf (file, "#hi ("); + msp430_print_operand_raw (file, XEXP (op, 0)); + fprintf (file, ")"); + break; + + default: + output_operand_lossage ("invalid zero extract"); + break; + } + break; + } + /* Fall through. */ + case CONST_INT: case SYMBOL_REF: case LABEL_REF: if (letter == 0) diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 65d6ad66df2..68b20090f51 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -1,5 +1,5 @@ /* GCC backend definitions for the TI MSP430 Processor - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of GCC. @@ -55,8 +55,8 @@ extern bool msp430x; "%{mcpu=*:-mcpu=%*}%{!mcpu=*:%{mmcu=*:-mmcu=%*}} " /* Pass the CPU type on to the assembler. */ \ "%{mrelax=-mQ} " /* Pass the relax option on to the assembler. */ \ "%{mlarge:-ml} " /* Tell the assembler if we are building for the LARGE pointer model. */ \ - "%{!msim:-md} %{msim:%{mlarge:-md}}" /* Copy data from ROM to RAM if necessary. */ \ - "%{ffunction-sections:-gdwarf-sections}" /* If function sections are being created then create DWARF line number sections as well. */ + "%{!msim:-md} %{msim:%{mlarge:-md}} " /* Copy data from ROM to RAM if necessary. */ \ + "%{ffunction-sections:-gdwarf-sections} " /* If function sections are being created then create DWARF line number sections as well. */ /* Enable linker section garbage collection by default, unless we are creating a relocatable binary (gc does not work) or debugging @@ -70,7 +70,6 @@ extern bool msp430x; -lgcc \ -lcrt \ %{msim:-lsim} \ -%{!msim:-lnosys} \ --end-group \ %{!T*:%{!msim:%{mmcu=*:--script=%*.ld}}} \ %{!T*:%{!msim:%{!mmcu=*:%Tmsp430.ld}}} \ @@ -112,9 +111,6 @@ extern bool msp430x; #define DOUBLE_TYPE_SIZE 64 #define LONG_DOUBLE_TYPE_SIZE 64 /*DOUBLE_TYPE_SIZE*/ -#define LIBGCC2_HAS_DF_MODE 1 -#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 - #define DEFAULT_SIGNED_CHAR 0 #define STRICT_ALIGNMENT 1 @@ -131,10 +127,9 @@ extern bool msp430x; #define MAX_REGS_PER_ADDRESS 1 #define Pmode (TARGET_LARGE ? PSImode : HImode) -/* Note: 32 is a lie. Large pointers are actually 20-bits wide. But gcc - thinks that any non-power-of-2 pointer size equates to BLKmode, which - causes all kinds of problems... */ -#define POINTER_SIZE (TARGET_LARGE ? 32 : 16) +#define POINTER_SIZE (TARGET_LARGE ? 20 : 16) +/* This is just for .eh_frame, to match bfd. */ +#define PTR_SIZE (TARGET_LARGE ? 4 : 2) #define POINTERS_EXTEND_UNSIGNED 1 #define ADDR_SPACE_NEAR 1 @@ -158,9 +153,9 @@ extern bool msp430x; /* Layout of Source Language Data Types */ #undef SIZE_TYPE -#define SIZE_TYPE (TARGET_LARGE ? "long unsigned int" : "unsigned int") +#define SIZE_TYPE (TARGET_LARGE ? "__int20 unsigned" : "unsigned int") #undef PTRDIFF_TYPE -#define PTRDIFF_TYPE (TARGET_LARGE ? "long int" : "int") +#define PTRDIFF_TYPE (TARGET_LARGE ? "__int20" : "int") #undef WCHAR_TYPE #define WCHAR_TYPE "long int" #undef WCHAR_TYPE_SIZE @@ -382,7 +377,7 @@ typedef struct #undef DWARF2_ADDR_SIZE #define DWARF2_ADDR_SIZE 4 -#define INCOMING_FRAME_SP_OFFSET (POINTER_SIZE / BITS_PER_UNIT) +#define INCOMING_FRAME_SP_OFFSET (TARGET_LARGE ? 4 : 2) #undef PREFERRED_DEBUGGING_TYPE #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index c0c97dae6bd..0110ed8ac1a 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -1,5 +1,5 @@ ;; Machine Description for TI MSP43* processors -;; Copyright (C) 2013-2014 Free Software Foundation, Inc. +;; Copyright (C) 2013-2015 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; This file is part of GCC. @@ -47,6 +47,15 @@ UNS_BIS_SR UNS_REFSYM_NEED_EXIT + + UNS_DELAY_32 + UNS_DELAY_32X + UNS_DELAY_16 + UNS_DELAY_16X + UNS_DELAY_2 + UNS_DELAY_1 + UNS_DELAY_START + UNS_DELAY_END ]) (include "predicates.md") @@ -170,6 +179,13 @@ MOV%X1.B\t%1, %0" ) +(define_insn "movqi_topbyte" + [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=r") + (subreg:QI (match_operand:PSI 1 "msp_general_operand" "r") 2))] + "msp430x" + "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0" +) + (define_insn "movqi" [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm") (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))] @@ -214,9 +230,9 @@ (match_operand:PSI 1 "msp_general_operand" "riYa,r,rmi"))] "" "@ - MOV%Q0\t%1, %0 - MOV%Q0\t%1, %0 - MOV%X0.%Q0\t%1, %0") + MOVA\t%1, %0 + MOVA\t%1, %0 + MOVX.A\t%1, %0") ; This pattern is identical to the truncsipsi2 pattern except ; that it uses a SUBREG instead of a TRUNC. It is needed in @@ -228,7 +244,7 @@ (define_insn "movsipsi2" [(set (match_operand:PSI 0 "register_operand" "=r") (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] - "TARGET_LARGE" + "msp430x" "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0" ) @@ -362,8 +378,8 @@ ; halves. (define_split [(set (match_operand:SI 0 "msp430_nonsubreg_operand") - (plus:SI (match_operand:SI 1 "nonimmediate_operand") - (match_operand:SI 2 "general_operand"))) + (plus:SI (match_operand:SI 1 "msp430_nonsubreg_operand") + (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand"))) ] "" [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm") @@ -386,14 +402,16 @@ operands[6] = msp430_subreg (HImode, operands[0], SImode, 2); operands[7] = msp430_subreg (HImode, operands[1], SImode, 2); operands[8] = msp430_subreg (HImode, operands[2], SImode, 2); + + /* BZ 64160: Do not use this splitter when the dest partially overlaps the source. */ + if (reg_overlap_mentioned_p (operands[3], operands[7]) + || reg_overlap_mentioned_p (operands[3], operands[8])) + FAIL; + if (GET_CODE (operands[5]) == CONST_INT) - { - operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff); - } + operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff); else - { - operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]); - } + operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]); " ) @@ -558,8 +576,8 @@ (define_insn "extendhipsi2" [(set (match_operand:PSI 0 "nonimmediate_operand" "=r") (subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0))] - "TARGET_LARGE" - "RLAM #4, %0 { RRAM #4, %0" + "msp430x" + "RLAM.A #4, %0 { RRAM.A #4, %0" ) ;; Look for cases where integer/pointer conversions are suboptimal due @@ -569,14 +587,14 @@ (define_insn "zero_extendhisi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))] - "TARGET_LARGE" + "msp430x" "MOV.W\t#0,%H0" ) (define_insn "zero_extendhisipsi2" [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r") (subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0))] - "TARGET_LARGE" + "msp430x" "@ AND.W\t#-1,%0 MOV.W\t%1,%0" @@ -586,16 +604,16 @@ [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) (const_int 1)))] - "TARGET_LARGE" - "RLAM #4, %0 { RRAM #3, %0" + "msp430x" + "RLAM.A #4, %0 { RRAM.A #3, %0" ) (define_insn "extend_and_shift2_hipsi2" [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) (const_int 2)))] - "TARGET_LARGE" - "RLAM #4, %0 { RRAM #2, %0" + "msp430x" + "RLAM.A #4, %0 { RRAM.A #2, %0" ) ; Nasty - we are sign-extending a 20-bit PSI value in one register into @@ -609,9 +627,15 @@ ; when the PSI value is negative.. ; ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... +; +; Note: We use a + constraint on operand 0 as otherwise GCC gets confused +; about extending a single PSI mode register into a pair of SImode registers +; with the same starting register. It thinks that the upper register of +; the pair is unused and so it can clobber it. Try compiling 20050826-2.c +; at -O2 to see this. (define_insn "zero_extendpsisi2" - [(set (match_operand:SI 0 "register_operand" "=r") + [(set (match_operand:SI 0 "register_operand" "+r") (zero_extend:SI (match_operand:PSI 1 "register_operand" "r")))] "" "* @@ -633,7 +657,7 @@ (define_insn "extendpsisi2" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))] - "TARGET_LARGE" + "msp430x" "* /* The intention here is that we copy the bottom 16-bits of %1 into %L0 (zeroing the top four bits). Then we copy the @@ -1162,7 +1186,7 @@ (clobber (reg:BI CARRY)) ] "" - "BIT%x0%X0%b0\t%1, %0 { JEQ\t%l2" + "BIT%x0%b0\t%1, %0 { JEQ\t%l2" ) (define_insn "*bitbranch<mode>4" @@ -1311,22 +1335,106 @@ "" "* if (REGNO (operands[0]) != REGNO (operands[1])) - return \"MOV.W\t%1, %0 { SUB.W\t#0, %0 { AND.W\t%2, %0\"; + return \"MOV.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; else - return \"SUB.W\t#0, %0 { AND.W\t%2, %0\"; + return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; " ) +(define_insn "delay_cycles_start" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] + UNS_DELAY_START)] + "" + "; Begin %J0 cycle delay" + ) + +(define_insn "delay_cycles_end" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] + UNS_DELAY_END)] + "" + "; End %J0 cycle delay" + ) + +(define_insn "delay_cycles_32" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i") + (match_operand 1 "immediate_operand" "i") + ] UNS_DELAY_32)] + "" + "PUSH r13 + PUSH r14 + MOV.W %A0, r13 + MOV.W %B0, r14 +1: SUB.W #1, r13 + SUBC.W #0, r14 + JNE 1b + TST.W r13 + JNE 1b + POP r14 + POP r13" + ) + +(define_insn "delay_cycles_32x" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i") + (match_operand 1 "immediate_operand" "i") + ] UNS_DELAY_32X)] + "" + "PUSHM.A #2,r13 + MOV.W %A0, r13 + MOV.W %B0, r14 +1: SUB.W #1, r13 + SUBC.W #0, r14 + JNE 1b + TST.W r13 + JNE 1b + POPM.A #2,r13" + ) + +(define_insn "delay_cycles_16" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i") + (match_operand 1 "immediate_operand" "i") + ] UNS_DELAY_16)] + "" + "PUSH r13 + MOV.W %0, r13 +1: SUB.W #1, r13 + JNE 1b + POP r13" + ) + +(define_insn "delay_cycles_16x" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i") + (match_operand 1 "immediate_operand" "i") + ] UNS_DELAY_16X)] + "" + "PUSHM.A #1,r13 + MOV.W %0, r13 +1: SUB.W #1, r13 + JNE 1b + POPM.A #1,r13" + ) + +(define_insn "delay_cycles_2" + [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] + "" + "JMP .+2" + ) + +(define_insn "delay_cycles_1" + [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] + "" + "NOP" + ) + (define_insn "mulhisi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "optimize > 2 && msp430_hwmult_enabled ()" + "optimize > 2 && msp430_hwmult_type != NONE" "* - if (msp430_is_f5_mcu ()) - return \"MOV.W %1, &0x04C2 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0\"; + if (msp430_use_f5_series_hwmult ()) + return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C2 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\"; else - return \"MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0\"; + return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " ) @@ -1334,12 +1442,12 @@ [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] - "optimize > 2 && msp430_hwmult_enabled ()" + "optimize > 2 && msp430_hwmult_type != NONE" "* - if (msp430_is_f5_mcu ()) - return \"MOV.W %1, &0x04C0 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0\"; + if (msp430_use_f5_series_hwmult ()) + return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x04C0 { MOV.W %2, &0x04C8 { MOV.W &0x04CA, %L0 { MOV.W &0x04CC, %H0 { POP.W sr\"; else - return \"MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0\"; + return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " ) @@ -1347,12 +1455,12 @@ [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] - "optimize > 2 && msp430_hwmult_enabled ()" + "optimize > 2 && msp430_hwmult_type != NONE" "* - if (msp430_is_f5_mcu ()) - return \"MOV.W %L1, &0x04D4 { MOV.W %H1, &0x04D6 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0\"; + if (msp430_use_f5_series_hwmult ()) + return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D4 { MOV.W %H1, &0x04D6 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\"; else - return \"MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0\"; + return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " ) @@ -1360,11 +1468,11 @@ [(set (match_operand:DI 0 "register_operand" "=r") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] - "optimize > 2 && msp430_hwmult_enabled ()" + "optimize > 2 && msp430_hwmult_type != NONE" "* - if (msp430_is_f5_mcu ()) - return \"MOV.W %L1, &0x04D0 { MOV.W %H1, &0x04D2 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0\"; + if (msp430_use_f5_series_hwmult ()) + return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x04D0 { MOV.W %H1, &0x04D2 { MOV.W %L2, &0x04E0 { MOV.W %H2, &0x04E2 { MOV.W &0x04E4, %A0 { MOV.W &0x04E6, %B0 { MOV.W &0x04E8, %C0 { MOV.W &0x04EA, %D0 { POP.W sr\"; else - return \"MOV.W %L1, &0x0140 { MOV.W %H1, &0x0141 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0\"; + return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0140 { MOV.W %H1, &0x0142 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " ) diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt index 5a447c0d2b0..8215013e846 100644 --- a/gcc/config/msp430/msp430.opt +++ b/gcc/config/msp430/msp430.opt @@ -7,19 +7,19 @@ Target Mask(ASM_HEX) Force assembly output to always use hex constants mmcu= -Target ToLower Joined RejectNegative Var(target_mcu) +Target Report ToLower Joined RejectNegative Var(target_mcu) Specify the MCU to build for. mcpu= -Target Joined RejectNegative Var(target_cpu) +Target Report Joined RejectNegative Var(target_cpu) Specify the ISA to build for: msp430, mdsp430x, msp430xv2 mlarge -Target Mask(LARGE) RejectNegative +Target Report Mask(LARGE) RejectNegative Select large model - 20-bit addresses/pointers msmall -Target InverseMask(LARGE) RejectNegative +Target Report InverseMask(LARGE) RejectNegative Select small model - 16-bit addresses/pointers (default) mrelax @@ -33,6 +33,27 @@ minrt Target Report Mask(MINRT) RejectNegative Use a minimum runtime (no static initializers or ctors) for memory-constrained devices. -mhwmult -Target Report Var(ENABLE_HWMULT, 1) Init(1) -Enable hardware multiply (except in interrupt routines) +HeaderInclude +config/msp430/msp430-opts.h + +mhwmult= +Target Joined RejectNegative Report ToLower Var(msp430_hwmult_type) Enum(msp430_hwmult_types) Init(AUTO) +Specify the type of hardware multiply to support + +Enum +Name(msp430_hwmult_types) Type(enum msp430_hwmult_types) + +EnumValue +Enum(msp430_hwmult_types) String(none) Value(NONE) + +EnumValue +Enum(msp430_hwmult_types) String(auto) Value(AUTO) + +EnumValue +Enum(msp430_hwmult_types) String(16bit) Value(SMALL) + +EnumValue +Enum(msp430_hwmult_types) String(32bit) Value(LARGE) + +EnumValue +Enum(msp430_hwmult_types) String(f5series) Value(F5SERIES) diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md index 9a8e2da0aa1..1331ff6b115 100644 --- a/gcc/config/msp430/predicates.md +++ b/gcc/config/msp430/predicates.md @@ -1,5 +1,5 @@ ;; Machine Description for TI MSP43* processors -;; Copyright (C) 2013-2014 Free Software Foundation, Inc. +;; Copyright (C) 2013-2015 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; This file is part of GCC. @@ -73,6 +73,10 @@ (define_predicate "msp430_nonsubreg_operand" (match_code "reg,mem")) +(define_predicate "msp430_nonsubreg_or_imm_operand" + (ior (match_operand 0 "msp430_nonsubreg_operand") + (match_operand 0 "immediate_operand"))) + ; TRUE for constants which are bit positions for zero_extract (define_predicate "msp430_bitpos" (and (match_code "const_int") diff --git a/gcc/config/msp430/t-msp430 b/gcc/config/msp430/t-msp430 index 74a3c529f6b..a5a837ad3fe 100644 --- a/gcc/config/msp430/t-msp430 +++ b/gcc/config/msp430/t-msp430 @@ -1,5 +1,5 @@ # Makefile fragment for building GCC for the TI MSP430 target. -# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# Copyright (C) 2012-2015 Free Software Foundation, Inc. # Contributed by Red Hat. # # This file is part of GCC. |