summaryrefslogtreecommitdiff
path: root/gcc/config/msp430
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/msp430')
-rw-r--r--gcc/config/msp430/constraints.md4
-rw-r--r--gcc/config/msp430/msp430-c.c11
-rw-r--r--gcc/config/msp430/msp430-modes.def1
-rw-r--r--gcc/config/msp430/msp430-opts.h32
-rw-r--r--gcc/config/msp430/msp430-protos.h16
-rw-r--r--gcc/config/msp430/msp430.c673
-rw-r--r--gcc/config/msp430/msp430.h23
-rw-r--r--gcc/config/msp430/msp430.md192
-rw-r--r--gcc/config/msp430/msp430.opt35
-rw-r--r--gcc/config/msp430/predicates.md6
-rw-r--r--gcc/config/msp430/t-msp4302
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.