diff options
author | Jozef Lawrynowicz <jozef.l@mittosystems.com> | 2019-10-07 15:58:19 +0000 |
---|---|---|
committer | Jozef Lawrynowicz <jozefl@gcc.gnu.org> | 2019-10-07 15:58:19 +0000 |
commit | 8682b1a508e5ba9bd2e1b2b4d298bf7d07a37f80 (patch) | |
tree | 0ca5ebb630b7aaee342feadcf29e07af6e22fd9b /gcc/config | |
parent | 0b06099d407225a28f12ed600ae561aa8317dfc9 (diff) | |
download | gcc-8682b1a508e5ba9bd2e1b2b4d298bf7d07a37f80.zip gcc-8682b1a508e5ba9bd2e1b2b4d298bf7d07a37f80.tar.gz gcc-8682b1a508e5ba9bd2e1b2b4d298bf7d07a37f80.tar.bz2 |
MSP430: Don't generate 430X insns when handling data in the lower memory region
gcc/ChangeLog:
2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* config.in: Regenerate.
* config/msp430/constraints.md: Fix docstring for "Ys" constraint.
Add new "Yx" constraint.
* config/msp430/driver-msp430.c (msp430_propagate_region_opt): New spec
function.
* config/msp430/msp430-protos.h (msp430_op_not_in_high_mem): New
prototype.
* config/msp430/msp430.c (msp430_option_override): Allow the lower
code/data region to be selected in the small memory model.
(msp430_section_attr): Don't warn if the "section" and "lower"
attributes are used together.
(msp430_handle_generic_attribute): Likewise.
(msp430_var_in_low_mem): New function.
(TARGET_ENCODE_SECTION_INFO): Define.
(msp430_encode_section_info): New function.
(gen_prefix): Return early in the small memory model.
Require TARGET_USE_LOWER_REGION_PREFIX to be set before adding the
".lower" prefix if -m{code,data}-region=lower have been passed.
(msp430_output_aligned_decl_common): Emit common symbols when
-mdata-region=lower is passed unless TARGET_USE_LOWER_REGION_PREFIX is
set.
(TARGET_ASM_FILE_END): Define.
(msp430_file_end): New function.
(msp430_do_not_relax_short_jumps): Allow relaxation when
function will be in the lower region.
(msp430_op_not_in_high_mem): New function.
(msp430_print_operand): Check "msp430_op_not_in_high_mem" for
the 'X' operand selector.
Clarify comment for 'x' operand selector.
* config/msp430/msp430.h (LINK_SPEC): Propagate
-m{code,data}-region to the linker via spec function
msp430_propagate_region_opt.
(msp430_propagate_region_opt): New prototype.
(EXTRA_SPEC_FUNCTIONS): Add msp430_propagate_region_opt.
(SYMBOL_FLAG_LOW_MEM): Define.
* config/msp430/msp430.md (addsipsi3): Add missing "%X" operand
selector.
(zero_extendqihi2): Fix operand number used by "%X" selector.
(zero_extendqisi2): Likewise.
(zero_extendhisi2): Likewise.
(movqi): Use "Yx" constraint in place of "%X" operand selector.
(movhi): Likewise.
(addqi3): Likewise.
(addhi3): Likewise.
(addsi3): Likewise.
(addhi3_cy): Likewise.
(addchi4_cy): Likewise.
(subqi3): Likewise.
(subhi3): Likewise.
(subsi3): Likewise.
(bic<mode>3): Likewise.
(and<mode>3): Likewise.
(ior<mode>3): Likewise.
(xor<mode>3): Likewise.
(slli_1): Add missing "%X" operand selector.
(slll_1): Likewise.
(slll_2): Likewise.
(srai_1): Likewise.
(sral_1): Likewise.
(sral_2): Likewise.
(srli_1): Likewise.
(srll_1): Likewise.
(cbranchqi4_real): Use "Yx" constraint in place of "%X" operand
selector.
(cbranchhi4_real): Likewise.
(cbranchqi4_reversed): Likewise.
(cbranchhi4_reversed): Likewise.
(*bitbranch<mode>4): Likewise.
(*bitbranch<mode>4_z): Remove unnecessary "%x" operand selector.
* config/msp430/msp430.opt (mcode-region=): Set default to
MSP430_REGION_LOWER. Improve docstring.
(mdata-region=): Likewise.
(muse-lower-region-prefix): New option.
* config/msp430/t-msp430 (MULTILIB_OPTIONS): Add
mdata-region=none multilib.
(MULTILIB_MATCHES): Set mdata-region={upper,either} to match
mdata-region=none multilib.
MULTILIB_EXCEPTIONS: Remove.
MULTILIB_REQUIRED: Define.
* configure: Regenerate.
* configure.ac: Define HAVE_AS_GNU_ATTRIBUTE and
HAVE_AS_MSPABI_ATTRIBUTE if GAS version >= 2.33.50.
* doc/extend.texi: Clarify comment for {upper,lower,either}
function attributes.
Add separate description for "lower" variable attribute.
gcc/testsuite/ChangeLog:
2019-10-07 Jozef Lawrynowicz <jozef.l@mittosystems.com>
* gcc.target/msp430/430x-insns.c: New test.
* gcc.target/msp430/data-attributes-2.c: Remove dg-warning
directives for conflicts between the "section" and "lower" attributes.
* gcc.target/msp430/msp430.exp
(check_effective_target_msp430_region_not_lower): New.
(check_effective_target_msp430_region_lower): New.
* gcc.target/msp430/object-attributes-430.c: New test.
* gcc.target/msp430/object-attributes-default.c: New test.
* gcc.target/msp430/object-attributes-mlarge-any-region.c: New test.
* gcc.target/msp430/object-attributes-mlarge.c: New test.
From-SVN: r276665
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/msp430/constraints.md | 10 | ||||
-rw-r--r-- | gcc/config/msp430/driver-msp430.c | 13 | ||||
-rw-r--r-- | gcc/config/msp430/msp430-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.c | 214 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.h | 13 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.md | 176 | ||||
-rw-r--r-- | gcc/config/msp430/msp430.opt | 12 | ||||
-rw-r--r-- | gcc/config/msp430/t-msp430 | 11 |
8 files changed, 326 insertions, 124 deletions
diff --git a/gcc/config/msp430/constraints.md b/gcc/config/msp430/constraints.md index 7ef249d..4422b2b 100644 --- a/gcc/config/msp430/constraints.md +++ b/gcc/config/msp430/constraints.md @@ -69,9 +69,11 @@ ;; 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. +;; because we know/assume they need not index across the 64K boundary. +;; Note that for a PSImode memory operand, we always need to use the X suffix, +;; regardless of what this constraint decides. (define_constraint "Ys" - "Memory reference, stack only." + "Memory reference, indexed or indirect register addressing modes." (and (match_code "mem") (ior (and (match_code "plus" "0") @@ -93,3 +95,7 @@ (match_test ("REGNO (XEXP (XEXP (op, 0), 0)) != SP_REGNO"))) )))) +(define_constraint "Yx" + "Memory reference, in lower memory below address 0x10000." + (and (match_code "mem") + (match_test "msp430_op_not_in_high_mem (op)"))) diff --git a/gcc/config/msp430/driver-msp430.c b/gcc/config/msp430/driver-msp430.c index 0a3d1e1..c37b169 100644 --- a/gcc/config/msp430/driver-msp430.c +++ b/gcc/config/msp430/driver-msp430.c @@ -149,3 +149,16 @@ msp430_select_hwmult_lib (int argc ATTRIBUTE_UNUSED, return "-lmul_none"; } + +/* Spec function. Propagate -m{code,data}-region= to the linker, unless the + lower region has been specified without -muse-lower-region-prefix also being + used. */ +const char * +msp430_propagate_region_opt (int argc, const char **argv) +{ + if (strcmp (argv[0], "lower") != 0) + return argv[0]; + else if ((argc == 2) && (strcmp (argv[1], "-muse-lower-region-prefix") == 0)) + return argv[0]; /* argv[0] == "lower". */ + return "none"; +} diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index 267b6f5..1c1757f 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -47,5 +47,6 @@ void msp430_split_movsi (rtx *); void msp430_start_function (FILE *, const char *, tree); rtx msp430_subreg (machine_mode, rtx, machine_mode, int); bool msp430_use_f5_series_hwmult (void); +bool msp430_op_not_in_high_mem (rtx op); #endif /* GCC_MSP430_PROTOS_H */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 6430823..354b4dd 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -35,6 +35,7 @@ #include "tm_p.h" #include "regs.h" #include "emit-rtl.h" +#include "varasm.h" #include "diagnostic-core.h" #include "fold-const.h" #include "stor-layout.h" @@ -263,9 +264,6 @@ msp430_option_override (void) else if (!TARGET_LARGE && msp430_code_region == MSP430_REGION_UPPER) error ("%<-mcode-region=upper%> requires the large memory model " "(%<-mlarge%>)"); - else if (!TARGET_LARGE && msp430_code_region == MSP430_REGION_LOWER) - error ("%<-mcode-region=lower%> requires the large memory model " - "(%<-mlarge%>)"); if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_EITHER) error ("%<-mdata-region=either%> requires the large memory model " @@ -273,10 +271,6 @@ msp430_option_override (void) else if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_UPPER) error ("%<-mdata-region=upper%> requires the large memory model " "(%<-mlarge%>)"); - else if (!TARGET_LARGE && msp430_data_region == MSP430_REGION_LOWER) - error ("%<-mdata-region=lower%> requires the large memory model " - "(%<-mlarge%>)"); - if (flag_exceptions || flag_non_call_exceptions || flag_unwind_tables || flag_asynchronous_unwind_tables) @@ -1386,7 +1380,7 @@ msp430_section_attr (tree * node, if (has_attr (ATTR_NOINIT, *node)) message = G_("ignoring attribute %qE because it conflicts with " "attribute %<noinit%>"); - else if (has_attr ("section", *node)) + else if (has_attr ("section", *node) && !TREE_NAME_EQ (name, "lower")) message = G_("ignoring attribute %qE because it conflicts with " "attribute %<section%>"); /* It does not make sense to use upper/lower/either attributes without @@ -1564,12 +1558,14 @@ msp430_handle_generic_attribute (tree *node, { const char *message = NULL; + /* The front end has set up an exclusion between the "noinit" and "section" + attributes. */ if (!(TREE_NAME_EQ (name, ATTR_NOINIT) || TREE_NAME_EQ (name, "section"))) return NULL_TREE; - /* The front end has set up an exclusion between the "noinit" and "section" - attributes. */ - if (has_attr (ATTR_LOWER, *node)) + /* We allow the "lower" attribute to be used on variables with the "section" + attribute. */ + if (has_attr (ATTR_LOWER, *node) && !TREE_NAME_EQ (name, "section")) message = G_("ignoring attribute %qE because it conflicts with " "attribute %<lower%>"); else if (has_attr (ATTR_UPPER, *node)) @@ -1591,6 +1587,55 @@ msp430_handle_generic_attribute (tree *node, return NULL_TREE; } +/* Given a non-automatic VAR_DECL which can possibly have a section, return + true if the variable will definitely be placed in the lower memory + region (below address 0x10000). */ +static bool +msp430_var_in_low_mem (tree decl) +{ + gcc_assert (VAR_P (decl)); + + /* "noinit" variables are always placed in the lower memory region. */ + if (has_attr (ATTR_UPPER, decl) + || has_attr (ATTR_EITHER, decl) + || has_attr (ATTR_PERSIST, decl) + /* Unless the variable is marked with the lower or noinit attribute, we + cannot assume that it is in the lower region if it is marked with the + section attribute or -mdata-region={upper,either,none} have been + passed. + The noinit and section attributes conflict. */ + || (!has_attr (ATTR_LOWER, decl) && !has_attr (ATTR_NOINIT, decl) + && (has_attr ("section", decl) + || msp430_data_region == MSP430_REGION_UPPER + || msp430_data_region == MSP430_REGION_EITHER + || msp430_data_region == MSP430_REGION_ANY))) + return false; + return true; +} + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO msp430_encode_section_info + +/* Encode whether a SYMBOL_REF is definitely in the lower memory region. */ +static void +msp430_encode_section_info (tree decl, rtx rtl, int first) +{ + rtx symbol; + default_encode_section_info (decl, rtl, first); + + /* Careful not to prod global register variables. */ + if (!MEM_P (rtl)) + return; + symbol = XEXP (rtl, 0); + if (GET_CODE (symbol) != SYMBOL_REF) + return; + + if (VAR_P (decl) + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) + && msp430_var_in_low_mem (decl)) + SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOW_MEM; +} + #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function @@ -1744,15 +1789,17 @@ gen_prefix (tree decl) if (has_section_name (".lowtext", decl)) return NULL; - /* If the object has __attribute__((lower)) then use the ".lower." prefix. */ + /* Memory regions require the large memory model. */ + if (!TARGET_LARGE) + return NULL; + + /* Note that we always apply the lower prefix when the attribute has been + used. But we only apply the lower prefix when the lower region has been + specified by a command line option if -muse-lower-region-prefix has also + been passed. */ if (has_attr (ATTR_LOWER, decl)) return lower_prefix; - /* If we are compiling for the MSP430 then we do not support the upper - region. */ - if (! msp430x) - return NULL; - if (has_attr (ATTR_UPPER, decl)) return upper_prefix; @@ -1761,7 +1808,8 @@ gen_prefix (tree decl) if (TREE_CODE (decl) == FUNCTION_DECL) { - if (msp430_code_region == MSP430_REGION_LOWER) + if ((msp430_code_region == MSP430_REGION_LOWER) + && TARGET_USE_LOWER_REGION_PREFIX) return lower_prefix; if (msp430_code_region == MSP430_REGION_UPPER) @@ -1772,7 +1820,8 @@ gen_prefix (tree decl) } else { - if (msp430_data_region == MSP430_REGION_LOWER) + if ((msp430_data_region == MSP430_REGION_LOWER) + && TARGET_USE_LOWER_REGION_PREFIX) return lower_prefix; if (msp430_data_region == MSP430_REGION_UPPER) @@ -1966,7 +2015,6 @@ msp430_unique_section (tree decl, int reloc) /* Emit a declaration of a common symbol. If a data region is in use then put the symbol into the equivalent .bss section instead. */ - void msp430_output_aligned_decl_common (FILE * stream, const tree decl, @@ -1976,7 +2024,9 @@ msp430_output_aligned_decl_common (FILE * stream, { /* Only emit a common symbol if the variable does not have a specific section assigned. */ - if (msp430_data_region == MSP430_REGION_ANY + if ((msp430_data_region == MSP430_REGION_ANY + || ((msp430_data_region == MSP430_REGION_LOWER) + && !TARGET_USE_LOWER_REGION_PREFIX)) && !(decl != NULL_TREE && DECL_SECTION_NAME (decl)) && !has_attr (ATTR_EITHER, decl) && !has_attr (ATTR_LOWER, decl) @@ -2021,6 +2071,78 @@ msp430_output_aligned_decl_common (FILE * stream, } } +#undef TARGET_ASM_FILE_END +#define TARGET_ASM_FILE_END msp430_file_end + +/* Emit MSPABI and GNU object attributes. + Tags and values for MSPABI attributes are: + OFBA_MSPABI_Tag_ISA 4 + MSP430 1 + MSP430X 2 + OFBA_MSPABI_Tag_Code_Model 6 + Small 1 + Large 2 + OFBA_MSPABI_Tag_Data_Model 8 + Small 1 + Large 2 + Restricted 3 (Unused by GNU) + OFBA_MSPABI_Tag_enum_size 10 (Unused by GNU) + Note that Code_Model and Data_Model are always equal for GNU. + We define a new .gnu_attribute to keep track of the data region used. + Tag_GNU_MSP430_Data_Region 4 + LOWER 1 + ANY 2 + See binutils-gdb/include/elf/msp430.h for the full details. */ +static void +msp430_file_end (void) +{ +#ifdef HAVE_AS_GNU_ATTRIBUTE + /* Enum for tag names. */ + enum + { + OFBA_MSPABI_Tag_ISA = 4, + OFBA_MSPABI_Tag_Code_Model = 6, + OFBA_MSPABI_Tag_Data_Model = 8, + Tag_GNU_MSP430_Data_Region = 4 + }; + /* Enum for tag values. */ + enum + { + OFBA_MSPABI_Val_ISA_MSP430 = 1, + OFBA_MSPABI_Val_ISA_MSP430X = 2, + OFBA_MSPABI_Val_Model_Small = 1, + OFBA_MSPABI_Val_Model_Large = 2, + Tag_GNU_MSP430_Data_Region_Lower = 1, + Tag_GNU_MSP430_Data_Region_Any = 2 + }; + /* .mspabi_attribute is a GNU assembler directive only. The assembler will + construct a .MSP430.attributes section based on the options it is invoked + with. The values it reads from these directives are used for validating + those options. */ + const char *msp_attr = ".mspabi_attribute"; + const char *gnu_attr = ".gnu_attribute"; + + /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_ISA. */ + fprintf (asm_out_file, "\t%s %d, %d\n", msp_attr, OFBA_MSPABI_Tag_ISA, + msp430x ? OFBA_MSPABI_Val_ISA_MSP430X : OFBA_MSPABI_Val_ISA_MSP430); + /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_Code_Model. */ + fprintf (asm_out_file, "\t%s %d, %d\n", msp_attr, OFBA_MSPABI_Tag_Code_Model, + TARGET_LARGE ? OFBA_MSPABI_Val_Model_Large + : OFBA_MSPABI_Val_Model_Small); + /* Emit .mspabi_attribute directive for OFBA_MSPABI_Tag_Data_Model. */ + fprintf (asm_out_file, "\t%s %d, %d\n", msp_attr, OFBA_MSPABI_Tag_Data_Model, + TARGET_LARGE ? OFBA_MSPABI_Val_Model_Large + : OFBA_MSPABI_Val_Model_Small); +#ifdef HAVE_AS_MSPABI_ATTRIBUTE + /* Emit .gnu_attribute directive for Tag_GNU_MSP430_Data_Region. */ + fprintf (asm_out_file, "\t%s %d, %d\n", gnu_attr, Tag_GNU_MSP430_Data_Region, + msp430_data_region == MSP430_REGION_LOWER + ? Tag_GNU_MSP430_Data_Region_Lower + : Tag_GNU_MSP430_Data_Region_Any); +#endif +#endif +} + bool msp430_do_not_relax_short_jumps (void) { @@ -2031,9 +2153,7 @@ msp430_do_not_relax_short_jumps (void) end up in a low section. */ return msp430_code_region == MSP430_REGION_EITHER - || msp430_code_region == MSP430_REGION_LOWER - || has_attr (ATTR_EITHER, current_function_decl) - || has_attr (ATTR_LOWER, current_function_decl); + || has_attr (ATTR_EITHER, current_function_decl); } enum msp430_builtin @@ -3074,6 +3194,36 @@ msp430_print_operand_addr (FILE * file, machine_mode /*mode*/, rtx addr) msp430_print_operand_raw (file, addr); } +/* Determine whether an RTX is definitely not a MEM referencing an address in + the upper memory region. Returns true if we've decided the address will be + in the lower memory region, or the RTX is not a MEM. Returns false + otherwise. */ +bool +msp430_op_not_in_high_mem (rtx op) +{ + rtx op0; + + if (!TARGET_LARGE || !MEM_P (op)) + return true; + + op0 = XEXP (op, 0); + + if (SYMBOL_REF_P (op0) && (SYMBOL_REF_FLAGS (op0) & SYMBOL_FLAG_LOW_MEM)) + /* msp430_encode_section_info decided this mem will be in lower + memory. */ + return true; + + /* Catch (mem (const (plus ((symbol_ref) (const_int))))) e.g. &addr+2. */ + if ((GET_CODE (op0) == CONST) + && (GET_CODE (XEXP (op0, 0)) == PLUS) + && (SYMBOL_REF_P (XEXP (XEXP (op0, 0), 0))) + && (SYMBOL_REF_FLAGS (XEXP (XEXP (op0, 0), 0)) & SYMBOL_FLAG_LOW_MEM)) + return true; + + /* Return false when undecided. */ + return false; +} + #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND msp430_print_operand @@ -3245,15 +3395,21 @@ 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 || GET_MODE (op) == PSImode) + opcode when we're using 20-bit addresses. + This can be used for insns which have only one operand which might be + a mem. + If an insn has two different operands which could be memory operands, + then the "Yx" constraint must be used to determine if the X suffix is + required by checking both operands. */ + if (GET_MODE (op) == PSImode + || !msp430_op_not_in_high_mem (op)) 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. */ return; case 'x': - /* Similarly, but only for PSImodes. BIC, for example, needs this. */ + /* Similarly, but only for PSImodes. BIC, and other insn patterns using + the QHI mode iterator (which includes, QI, HI, and PSImode) use + this. */ if (GET_MODE (op) == PSImode) fprintf (file, "X"); return; diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 3449bd4..f885de2 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -71,7 +71,10 @@ extern bool msp430x; is enabled (the GDB testsuite relies upon unused entities not being deleted). */ #define LINK_SPEC "%{mrelax:--relax} %{mlarge:%{!r:%{!g:--gc-sections}}} " \ - "%{mcode-region=*:--code-region=%*} %{mdata-region=*:--data-region=%*}" + "%{mcode-region=*:--code-region=%:" \ + "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \ + "%{mdata-region=*:--data-region=%:" \ + "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \ #define DRIVER_SELF_SPECS \ " %{!mlarge:%{mcode-region=*:%{mdata-region=*:%e-mcode-region and " \ @@ -90,12 +93,16 @@ extern const char * msp430_select_hwmult_lib (int, const char **); extern const char * msp430_select_cpu (int, const char **); extern const char * msp430_set_driver_var (int, const char **); extern const char * msp430_check_path_for_devices (int, const char **); +extern const char *msp430_propagate_region_opt (int, const char **); +/* There must be a trailing comma after the last item, see gcc.c + "static_spec_functions". */ # define EXTRA_SPEC_FUNCTIONS \ { "msp430_hwmult_lib", msp430_select_hwmult_lib }, \ { "msp430_select_cpu", msp430_select_cpu }, \ { "msp430_set_driver_var", msp430_set_driver_var }, \ - { "msp430_check_path_for_devices", msp430_check_path_for_devices }, + { "msp430_check_path_for_devices", msp430_check_path_for_devices }, \ + { "msp430_propagate_region_opt", msp430_propagate_region_opt }, /* Specify the libraries to include on the linker command line. @@ -482,3 +489,5 @@ typedef struct #define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \ msp430_output_aligned_decl_common ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) + +#define SYMBOL_FLAG_LOW_MEM (SYMBOL_FLAG_MACH_DEP << 0) diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index f6d6889..c72f7aa 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -190,22 +190,22 @@ ) (define_insn "movqi" - [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm") - (match_operand:QI 1 "msp_general_operand" "riYs,rmi"))] + [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYsYx,rm") + (match_operand:QI 1 "msp_general_operand" "riYsYx,rmi"))] "" "@ MOV.B\t%1, %0 - MOV%X0.B\t%1, %0" + MOVX.B\t%1, %0" ) (define_insn "movhi" - [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rYs,rm") - (match_operand:HI 1 "msp_general_operand" "N,riYs,rmi"))] + [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rYsYx,rm") + (match_operand:HI 1 "msp_general_operand" "N,riYsYx,rmi"))] "" "@ MOV.B\t%1, %0 MOV.W\t%1, %0 - MOV%X0.W\t%1, %0" + MOVX.W\t%1, %0" ) (define_expand "movsi" @@ -241,7 +241,7 @@ "msp430_split_movsi (operands);" ) -;; Some MOVX.A cases can be done with MOVA, this is only a few of them. +;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them. (define_insn "movpsi" [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,r,r,Ya,rm") (match_operand:PSI 1 "msp_general_operand" "N,O,riYa,r,rmi"))] @@ -289,23 +289,23 @@ ) (define_insn "addqi3" - [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYs,rm") + [(set (match_operand:QI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (plus:QI (match_operand:QI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:QI 2 "msp_general_operand" "riYs,rmi")))] + (match_operand:QI 2 "msp_general_operand" "riYsYx,rmi")))] "" "@ ADD.B\t%2, %0 - ADD%X0.B\t%2, %0" + ADDX.B\t%2, %0" ) (define_insn "addhi3" - [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYs,rm") + [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:HI 2 "msp_general_operand" "riYs,rmi")))] + (match_operand:HI 2 "msp_general_operand" "riYsYx,rmi")))] "" "@ ADD.W\t%2, %0 - ADD%X0.W\t%2, %0" + ADDX.W\t%2, %0" ) ; This pattern is needed in order to avoid reload problems. @@ -317,17 +317,17 @@ (plus:SI (match_operand:SI 1 "register_operand" "0") (match_operand 2 "general_operand" "rmi")))] "" - "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0" + "ADD%X2.W\t%L2, %L0 { ADDC%X2.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0" ) (define_insn "addsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm") + [(set (match_operand:SI 0 "nonimmediate_operand" "=&rYsYx,rm") (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "r,mi")))] + (match_operand:SI 2 "general_operand" "rYsYxi,mi")))] "" "@ ADD\t%L2, %L0 { ADDC\t%H2, %H0 - ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0" + ADDX\t%L2, %L0 { ADDCX\t%H2, %H0" ) ; Version of addhi that exposes the carry operations, for SImode adds. @@ -358,9 +358,9 @@ ; that are not single_set() very well. (define_insn "addhi3_cy" - [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm") + [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:HI 2 "msp_nonimmediate_operand" "r,rm"))) + (match_operand:HI 2 "msp_nonimmediate_operand" "rYsYxi,rm"))) (set (reg:BI CARRY) (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) (zero_extend:SI (match_dup 2))) @@ -369,7 +369,7 @@ "" "@ ADD\t%2, %1 ; cy - ADD%X0\t%2, %1 ; cy" + ADDX\t%2, %1 ; cy" ) (define_insn "addhi3_cy_i" @@ -389,15 +389,15 @@ ; Version of addhi that adds the carry, for SImode adds. (define_insn "addchi4_cy" - [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=r,rm") + [(set (match_operand:HI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (plus:HI (plus:HI (match_operand:HI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:HI 2 "msp_general_operand" "ri,rmi")) + (match_operand:HI 2 "msp_general_operand" "riYsYx,rmi")) (zero_extend:HI (reg:BI CARRY)))) ] "" "@ ADDC\t%2, %1 - ADDC%X0\t%2, %1" + ADDCX\t%2, %1" ) ; Split an SImode add into two HImode adds, keeping track of the carry @@ -458,36 +458,38 @@ ;; Alternatives 2 and 3 are to handle cases generated by reload. (define_insn "subqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") + [(set (match_operand:QI 0 "nonimmediate_operand" "=rYsYx, rm, &?r, ?&r") (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i") - (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r")))] + (match_operand:QI 2 "general_operand" " riYsYx, rmi, rmi, r")))] "" "@ SUB.B\t%2, %0 - SUB%X0.B\t%2, %0 - MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0 + SUBX.B\t%2, %0 + MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0 MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" ) ;; Alternatives 2 and 3 are to handle cases generated by reload. (define_insn "subhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYsYx, rm, &?r, ?&r") (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i") - (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r")))] + (match_operand:HI 2 "general_operand" " riYsYx, rmi, rmi, r")))] "" "@ SUB.W\t%2, %0 - SUB%X0.W\t%2, %0 - MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0 + SUBX.W\t%2, %0 + MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0 MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" ) (define_insn "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm") - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "general_operand" "rmi")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=&rYsYx,m") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "riYsYx,mi")))] "" - "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0" + "@ + SUB\t%L2, %L0 { SUBC\t%H2, %H0 + SUBX\t%L2, %L0 { SUBCX\t%H2, %H0" ) (define_insn "*bic<mode>_cg" @@ -501,44 +503,44 @@ ) (define_insn "bic<mode>3" - [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") - (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn")) + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYsYx,rm") + (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYsYx,rmn")) (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))] "" "@ BIC%x0%b0\t%1, %0 - BIC%X0%b0\t%1, %0" + BICX%b0\t%1, %0" ) (define_insn "and<mode>3" - [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=r,rYs,rm") + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=r,rYsYx,rm") (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0,0") - (match_operand:QHI 2 "msp_general_operand" "N,riYs,rmi")))] + (match_operand:QHI 2 "msp_general_operand" "N,riYsYx,rmi")))] "" "@ AND%x0.B\t%2, %0 AND%x0%b0\t%2, %0 - AND%X0%b0\t%2, %0" + ANDX%b0\t%2, %0" ) (define_insn "ior<mode>3" - [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))] + (match_operand:QHI 2 "msp_general_operand" "riYsYx,rmi")))] "" "@ BIS%x0%b0\t%2, %0 - BIS%X0%b0\t%2, %0" + BISX%b0\t%2, %0" ) (define_insn "xor<mode>3" - [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYsYx,rm") (xor:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") - (match_operand:QHI 2 "msp_general_operand" "riYs,rmi")))] + (match_operand:QHI 2 "msp_general_operand" "riYsYx,rmi")))] "" "@ XOR%x0%b0\t%2, %0 - XOR%X0%b0\t%2, %0" + XORX%b0\t%2, %0" ) ;; Macro : XOR #~0, %0 @@ -567,7 +569,7 @@ "@ AND\t#0xff, %0 MOV.B\t%1, %0 - MOV%X0.B\t%1, %0 + MOV%X1.B\t%1, %0 AND%X0\t#0xff, %0" ) @@ -621,7 +623,7 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=r") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rm")))] "" - "MOV.B\t%1,%L0 { CLR\t%H0" + "MOV%X1.B\t%1,%L0 { CLR\t%H0" ) (define_insn "zero_extendhisi2" @@ -629,7 +631,7 @@ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")))] "" "@ - MOV.W\t#0,%H0 + MOV%X0.W\t#0,%H0 MOV.W\t%1,%L0 { MOV.W\t#0,%H0" ) @@ -782,7 +784,7 @@ (ashift:HI (match_operand:HI 1 "general_operand" "0") (const_int 1)))] "" - "RLA.W\t%0" ;; Note - this is a macro for ADD + "RLA%X0.W\t%0" ;; Note - this is a macro for ADD ) (define_insn "430x_shift_left" @@ -802,7 +804,7 @@ (ashift:SI (match_operand:SI 1 "general_operand" "0") (const_int 1)))] "" - "RLA.W\t%L0 { RLC.W\t%H0" + "RLA%X0.W\t%L0 { RLC%X0.W\t%H0" ) (define_insn "slll_2" @@ -810,7 +812,7 @@ (ashift:SI (match_operand:SI 1 "general_operand" "0") (const_int 2)))] "" - "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0" + "RLA%X0.W\t%L0 { RLC%X0.W\t%H0 { RLA%X0.W\t%L0 { RLC%X0.W\t%H0" ) (define_expand "ashlsi3" @@ -867,7 +869,7 @@ (ashiftrt:HI (match_operand:HI 1 "msp_general_operand" "0") (const_int 1)))] "" - "RRA.W\t%0" + "RRA%X0.W\t%0" ) (define_insn "430x_arithmetic_shift_right" @@ -903,7 +905,7 @@ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") (const_int 1)))] "" - "RRA.W\t%H0 { RRC.W\t%L0" + "RRA%X0.W\t%H0 { RRC%X0.W\t%L0" ) (define_insn "sral_2" @@ -911,7 +913,7 @@ (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") (const_int 2)))] "" - "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0" + "RRA%X0.W\t%H0 { RRC%X0.W\t%L0 { RRA%X0.W\t%H0 { RRC%X0.W\t%L0" ) (define_expand "ashrsi3" @@ -968,7 +970,7 @@ (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") (const_int 1)))] "" - "CLRC { RRC.W\t%0" + "CLRC { RRC%X0.W\t%0" ) (define_insn "430x_logical_shift_right" @@ -994,7 +996,7 @@ (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") (const_int 1)))] "" - "CLRC { RRC.W\t%H0 { RRC.W\t%L0" + "CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0" ) (define_insn "srll_2x" @@ -1188,8 +1190,8 @@ (define_insn "cbranchqi4_real" [(set (pc) (if_then_else (match_operator 0 "msp430_cmp_operator" - [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm") - (match_operand:QI 2 "general_operand" "rYsi,rmi")]) + [(match_operand:QI 1 "nonimmediate_operand" "rYsYx,rm") + (match_operand:QI 2 "general_operand" "rYsYxi,rmi")]) (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) @@ -1197,14 +1199,14 @@ "" "@ CMP.B\t%2, %1 { J%0\t%l3 - CMP%X0.B\t%2, %1 { J%0\t%l3" + CMPX.B\t%2, %1 { J%0\t%l3" ) (define_insn "cbranchhi4_real" [(set (pc) (if_then_else (match_operator 0 "msp430_cmp_operator" - [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm") - (match_operand:HI 2 "general_operand" "rYsi,rmi")]) + [(match_operand:HI 1 "nonimmediate_operand" "rYsYx,rm") + (match_operand:HI 2 "general_operand" "rYsYxi,rmi")]) (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) @@ -1222,12 +1224,12 @@ { return which_alternative == 0 ? \"CMP.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\" : - \"CMP%X0.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\"; + \"CMPX.W\t%2, %1 { J%r0 1f { BRA #%l3 { 1:\"; } return which_alternative == 0 ? \"CMP.W\t%2, %1 { J%0\t%l3\" : - \"CMP%X0.W\t%2, %1 { J%0\t%l3\"; + \"CMPX.W\t%2, %1 { J%0\t%l3\"; " [(set (attr "length") (if_then_else @@ -1257,8 +1259,8 @@ (define_insn "cbranchqi4_reversed" [(set (pc) (if_then_else (match_operator 0 "msp430_reversible_cmp_operator" - [(match_operand:QI 1 "general_operand" "rYsi,rmi") - (match_operand:QI 2 "general_operand" "rYs,rm")]) + [(match_operand:QI 1 "general_operand" "rYsYxi,rmi") + (match_operand:QI 2 "general_operand" "rYsYx,rm")]) (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) @@ -1266,14 +1268,14 @@ "" "@ CMP.B\t%1, %2 { J%R0\t%l3 - CMP%X0.B\t%1, %2 { J%R0\t%l3" + CMPX.B\t%1, %2 { J%R0\t%l3" ) (define_insn "cbranchhi4_reversed" [(set (pc) (if_then_else (match_operator 0 "msp430_reversible_cmp_operator" - [(match_operand:HI 1 "general_operand" "rYsi,rmi") - (match_operand:HI 2 "general_operand" "rYs,rm")]) + [(match_operand:HI 1 "general_operand" "rYsYxi,rmi") + (match_operand:HI 2 "general_operand" "rYsYx,rm")]) (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) @@ -1281,13 +1283,13 @@ "" "@ CMP.W\t%1, %2 { J%R0\t%l3 - CMP%X0.W\t%1, %2 { J%R0\t%l3" + CMPX.W\t%1, %2 { J%R0\t%l3" ) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else - (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm") - (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi")) + (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYsYx,rm") + (match_operand:QHI 1 "msp_general_operand" "rYsYxi,rmi")) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc))) @@ -1296,46 +1298,52 @@ "" "@ BIT%x0%b0\t%1, %0 { JNE\t%l2 - BIT%X0%b0\t%1, %0 { JNE\t%l2" + BITX%b0\t%1, %0 { JNE\t%l2" ) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else - (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") - (match_operand:QHI 1 "msp_general_operand" "rmi")) + (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYsYx,rm") + (match_operand:QHI 1 "msp_general_operand" "rYsYxi,rmi")) (const_int 0)) (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] "" - "BIT%x0%b0\t%1, %0 { JEQ\t%l2" + "@ + BIT%x0%b0\t%1, %0 { JEQ\t%l2 + BITX%b0\t%1, %0 { JEQ\t%l2" ) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else - (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") - (match_operand:QHI 1 "msp_general_operand" "rmi")) + (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYsYx,rm") + (match_operand:QHI 1 "msp_general_operand" "rYsYxi,rmi")) (const_int 0)) (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" - "BIT%X0%b0\t%1, %0 { JNE\t%l2" + "@ + BIT%x0%b0\t%1, %0 { JNE\t%l2 + BITX%b0\t%1, %0 { JNE\t%l2" ) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else - (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") - (match_operand:QHI 1 "msp_general_operand" "rmi")) + (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYsYx,rm") + (match_operand:QHI 1 "msp_general_operand" "rYsYxi,rmi")) (const_int 0)) (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" - "BIT%X0%b0\t%1, %0 { JEQ\t%l2" + "@ + BIT%x0%b0\t%1, %0 { JEQ\t%l2 + BITX%b0\t%1, %0 { JEQ\t%l2" ) ;;------------------------------------------------------------ @@ -1368,7 +1376,7 @@ (clobber (reg:BI CARRY)) ] "" - "BIT%x0%X0%b0\t%p1, %0 { JEQ\t%l2" + "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" ) (define_insn "*bitbranch<mode>4_z" diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt index cbbe0fa..2db2906 100644 --- a/gcc/config/msp430/msp430.opt +++ b/gcc/config/msp430/msp430.opt @@ -67,12 +67,16 @@ EnumValue Enum(msp430_hwmult_types) String(f5series) Value(MSP430_HWMULT_F5SERIES) mcode-region= -Target Joined RejectNegative Report ToLower Var(msp430_code_region) Enum(msp430_regions) Init(MSP430_REGION_ANY) -Specify whether functions should be placed into low or high memory. +Target Joined RejectNegative Report ToLower Var(msp430_code_region) Enum(msp430_regions) Init(MSP430_REGION_LOWER) +Specify whether functions should be placed into the lower or upper memory regions, or if they should be shuffled between the regions (either) for best fit (default: lower). mdata-region= -Target Joined RejectNegative Report ToLower Var(msp430_data_region) Enum(msp430_regions) Init(MSP430_REGION_ANY) -Specify whether variables should be placed into low or high memory. +Target Joined RejectNegative Report ToLower Var(msp430_data_region) Enum(msp430_regions) Init(MSP430_REGION_LOWER) +Specify whether variables should be placed into the lower or upper memory regions, or if they should be shuffled between the regions (either) for best fit (default: lower). + +muse-lower-region-prefix +Target Mask(USE_LOWER_REGION_PREFIX) Report +Add the .lower prefix to section names when compiling with -m{code,data}-region=lower (disabled by default). Enum Name(msp430_regions) Type(enum msp430_regions) diff --git a/gcc/config/msp430/t-msp430 b/gcc/config/msp430/t-msp430 index b956510..f8ba775 100644 --- a/gcc/config/msp430/t-msp430 +++ b/gcc/config/msp430/t-msp430 @@ -28,17 +28,22 @@ msp430-devices.o: $(srcdir)/config/msp430/msp430-devices.c \ # Enable multilibs: -MULTILIB_OPTIONS = mcpu=msp430 mlarge -MULTILIB_DIRNAMES = 430 large +MULTILIB_OPTIONS = mcpu=msp430 mlarge mdata-region=none +MULTILIB_DIRNAMES = 430 large full-memory-range # Match -mcpu=430 MULTILIB_MATCHES = mcpu?msp430=mcpu?430 +# These options are equivalent in terms of the multilib required for them +MULTILIB_MATCHES += mdata-region?none=mdata-region?upper +MULTILIB_MATCHES += mdata-region?none=mdata-region?either # The correct multilib for a given mmcu is selected without the need for # hard-coded data here, because DRIVER_SELF_SPECS will place the correct # -mcpu option for a given mcu onto the command line. -MULTILIB_EXCEPTIONS = mcpu=msp430/mlarge +MULTILIB_REQUIRED = mcpu=msp430 +MULTILIB_REQUIRED += mlarge +MULTILIB_REQUIRED += mlarge/mdata-region=none MULTILIB_EXTRA_OPTS = |