+2014-04-23 Nick Clifton <nickc@redhat.com>
+
+ * config/msp430/msp430.c (msp430_handle_option): Move function
+ to msp430-common.c
+ (msp430_option_override): Simplify mcu and mcpu option handling.
+ (msp430_is_f5_mcu): Rename to msp430_use_f5_series_hwmult. Add
+ support for -mhwmult command line option.
+ (has_32bit_hwmult): Rename to use_32bit_hwmult. Add support for
+ -mhwmult command line option.
+ (msp430_hwmult_enabled): Delete.
+ (msp43o_output_labelref): Add support for -mhwmult command line
+ option.
+ * config/msp430/msp430.md (mulhisi3, umulhisi3, mulsidi3)
+ (umulsidi3): Likewise.
+ * config/msp430/msp430.opt (mmcu): Add Report attribute.
+ (mcpu, mlarge, msmall): Likewise.
+ (mhwmult): New option.
+ * config/msp430/msp430-protos.h (msp430_hwmult_enabled): Remove
+ prototype.
+ (msp430_is_f5_mcu): Remove prototype.
+ (msp430_use_f5_series_hwmult): Add prototype.
+ * config/msp430/msp430-opts.h: New file.
+ * common/config/msp430: New directory.
+ * common/config/msp430/msp430-common.c: New file.
+ * config.gcc (msp430): Remove target_has_targetm_common.
+ * doc/invoke.texi: Document -mhwmult command line option.
+
2014-04-23 Nick Clifton <nickc@redhat.com>
* config/i386/cygwin.h (ENDFILE_SPEC): Include
--- /dev/null
+/* Common hooks for Texas Instruments MSP430.
+ Copyright (C) 2014 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+#include "opts.h"
+#include "flags.h"
+
+/* Handle -mcpu= and -mmcu= here. We want to ensure that only one
+ of these two options - the last specified on the command line -
+ is passed on to the msp430 backend. */
+
+static bool
+msp430_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
+ struct gcc_options *opts_set ATTRIBUTE_UNUSED,
+ const struct cl_decoded_option *decoded,
+ location_t loc ATTRIBUTE_UNUSED)
+{
+ switch (decoded->opt_index)
+ {
+ case OPT_mcpu_:
+ if (strcasecmp (decoded->arg, "msp430x") == 0
+ || strcasecmp (decoded->arg, "msp430xv2") == 0
+ || strcasecmp (decoded->arg, "430x") == 0
+ || strcasecmp (decoded->arg, "430xv2") == 0)
+ {
+ target_cpu = "msp430x";
+ target_mcu = NULL;
+ }
+ else if (strcasecmp (decoded->arg, "msp430") == 0
+ || strcasecmp (decoded->arg, "430") == 0)
+ {
+ target_cpu = "msp430";
+ target_mcu = NULL;
+ }
+ else
+ {
+ error ("unrecognised argument of -mcpu: %s", decoded->arg);
+ return false;
+ }
+ break;
+
+ case OPT_mmcu_:
+ /* 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 (decoded->arg, "msp430") == 0)
+ {
+ target_cpu = "msp430";
+ target_mcu = NULL;
+ }
+ else if (strcasecmp (decoded->arg, "msp430x") == 0
+ || strcasecmp (decoded->arg, "msp430xv2") == 0)
+ {
+ target_cpu = "msp430x";
+ target_mcu = NULL;
+ }
+ else
+ target_cpu = NULL;
+ break;
+ }
+
+ return true;
+}
+
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION msp430_handle_option
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
c_target_objs="msp430-c.o"
cxx_target_objs="msp430-c.o"
- target_has_targetm_common=no
tmake_file="${tmake_file} msp430/t-msp430"
;;
nds32le-*-*)
--- /dev/null
+/* GCC option-handling definitions for the TI MSP430
+ Copyright (C) 2014 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
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);
-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);
void msp430_split_movsi (rtx *);
void msp430_start_function (FILE *, const char *, tree);
rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int);
+bool msp430_use_f5_series_hwmult (void);
#endif /* GCC_MSP430_PROTOS_H */
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
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;
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. */
}
/* Returns true if the current MCU is an F5xxx series. */
bool
-msp430_is_f5_mcu (void)
+msp430_use_f5_series_hwmult (void)
{
- if (target_mcu == NULL)
+ if (msp430_hwmult_type == F5SERIES)
+ return true;
+
+ if (target_mcu == NULL || msp430_hwmult_type != AUTO)
return false;
+
return strncasecmp (target_mcu, "msp430f5", 8) == 0;
}
/* Returns true id 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 [] =
{
"msp430f47177", "msp430f47187", "msp430f47197"
};
int i;
- if (target_mcu == NULL)
+
+ if (msp430_hwmult_type == LARGE)
+ return true;
+
+ if (target_mcu == NULL || msp430_hwmult_type != AUTO)
return false;
for (i = ARRAY_SIZE (known_32bit_mult_mcus); i--;)
return false;
}
-/* Returns true if hardware multiply is supported by the chosen MCU. */
-bool
-msp430_hwmult_enabled (void)
-{
- if (target_mcu == NULL)
- return false;
-
- if (!ENABLE_HWMULT)
- return false;
-
- if (msp430_is_interrupt_func ())
- return false;
-
- if (msp430_is_f5_mcu () || has_32bit_hw_mult ())
- return true;
-
- return false;
-}
-
/* This function does the same as the default, but it will replace GCC
function names with the MSPABI-specified ones. */
void
/* 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
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
name = "__mulsi2";
[(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 && ! msp430_is_interrupt_func ()"
"*
- 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 { 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 { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\";
"
)
[(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 { 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 { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\";
"
)
[(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 { 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 { 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\";
"
)
[(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 { 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 { 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 { POP.W sr\";
"
)
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
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)
)
(define_insn "*movhi_virt"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=vYS,v,Wfr")
- (match_operand:HI 1 "general_operand" "viYS,Wfr,v"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=vS, Y, v, Wfr")
+ (match_operand:HI 1 "general_operand" "viYS, viS, Wfr, v"))]
"rl78_virt_insns_ok ()"
"v.movw %0, %1"
[(set_attr "valloc" "op1")]
@gccoptlist{-meb -mel -mno-crt0}
@emph{MSP430 Options}
-@gccoptlist{-msim -masm-hex -mmcu= -mcpu= -mlarge -msmall -mrelax}
+@gccoptlist{-msim -masm-hex -mmcu= -mcpu= -mlarge -msmall -mrelax @gol
+-mhwmult=}
@emph{NDS32 Options}
@gccoptlist{-mbig-endian -mlittle-endian @gol
linker to perform certain optimizations that cannot be done until
the final link.
+@item mhwmult=
+@opindex mhwmult=
+Describes the type of hardware multiply supported by the target.
+Accepted values are @code{none} for no hardware multiply, @code{16bit}
+for the original 16-bit-only multiply supported by early MCUs.
+@code{32bit} for the 16/32-bit multiply supported by later MCUs and
+@code{f5series} for the 16/32-bit multiply supported by F5-series MCUs.
+A value of @code{auto} can also be given. This tells GCC to deduce
+the hardware multiply support based upon the MCU name provided by the
+@option{-mmcu} option. If no @option{-mmcu} option is specified then
+@code{32bit} hardware multiply support is assumed. @code{auto} is the
+default setting.
+
+Hardware multiplies are normally performed by calling a library
+routine. This saves space in the generated code. When compiling at
+@code{-O3} or higher however the hardware multiplier is invoked
+inline. This makes for bigger, but faster code.
+
+The hardware multiply routines disable interrupts whilst running and
+restore the previous interrupt state when they finish. This makes
+them safe to use inside interrupt handlers as well as in normal code.
+
@end table
@node NDS32 Options