From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 48344 invoked by alias); 5 May 2015 15:14:01 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 48327 invoked by uid 89); 5 May 2015 15:13:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_50,KAM_ASCII_DIVIDERS,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 05 May 2015 15:13:56 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t45FDsUN027577 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Tue, 5 May 2015 11:13:55 -0400 Received: from littlehelper.redhat.com (vpn1-7-63.ams2.redhat.com [10.36.7.63]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t45FDqkB006331 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 5 May 2015 11:13:53 -0400 From: Nick Clifton To: gcc-patches@gcc.gnu.org Subject: Commit: MSP430: Add -mcode-region= and -mdata-region= options Date: Tue, 05 May 2015 15:14:00 -0000 Message-ID: <87383bdplb.fsf@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-IsSubscribed: yes X-SW-Source: 2015-05/txt/msg00340.txt.bz2 --=-=-= Content-Type: text/plain Content-length: 2384 Hi Guys, I am applying the attached patch to add two new command line options to the MSP430 backend. The -mcode-region= and -mdata-region= options allow the user to specify whether functions and data should be placed into low memory (below 64K) or high memory. This only applies to the MSP430X, and only when the specific MSP430 part actually has both low and high memory regions. An interesting ability of this new feature is to select a memory region of "either", which tells the linker to place the object into low memory if there is room available and into high memory otherwise. Three new function and data attributes have also been added - lower, either and upper - which allow the programmer to explicitly state which memory region an object should use. Tested with no regressions and 77 less unexpected failures on an msp430-elf toolchain. Cheers Nick gcc/ChangeLog 2015-05-05 Nick Clifton * config/msp430/msp430-opts.h (enum msp430_regions): New. * config/msp430/msp430.c (msp430_override_options): Complain if -mcode-region or -mdata-region is used on a non MSP430X. (msp430_section_attr): New function. Checks lower, upper and either attributes. (msp430_attribute_table): Add lower, upper and either. (gen_prefix): New function. Generates a prefix for a section name. (msp430_select_section): New function - handles the choice of section for an object. Takes into account memory region attributes and options. (msp430_function_section): Use gen_prefix. (TARGET_SECTION_TYPE_FLAGS): Define. (msp430_section_type_flags): New function. (TARGET_ASM_UNIQUE_SECTION): Define. (msp430_unique_section): New function. (msp430_output_aligned_decl_common): New function. (msp430_do_not_relax_short_jumps): New function. * config/msp430/msp430.h (USE_SELECT_SECTION_FOR_FUNCTIONS): Define. (ASM_OUTPUT_ALIGNED_DECL_COMMON): Define. * config/msp430/msp430-protos.h (msp430_do_not_relax_short_jumps): New prototype. (msp430_output_aligned_decl_common): New prototype. * config/msp430/msp430.md (length): New attribute. (cbranchhi4_real): If msp430_do_not_relax_short_jumps is true then use a long code sequence for short jumps. * config/msp430/msp430.opt (mcode-region): New. (mdata-region): New. * doc/invoke.texi: Document new options. * doc/extend.texi: Document new attributes. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=msp430.memory-regions.patch Content-length: 26769 Index: gcc/config/msp430/msp430-opts.h =================================================================== --- gcc/config/msp430/msp430-opts.h (revision 222796) +++ gcc/config/msp430/msp430-opts.h (working copy) @@ -29,4 +29,12 @@ F5SERIES }; +enum msp430_regions +{ + ANY, + EITHER, + LOWER, + UPPER +}; + #endif Index: gcc/config/msp430/msp430-protos.h =================================================================== --- gcc/config/msp430/msp430-protos.h (revision 222796) +++ gcc/config/msp430/msp430-protos.h (working copy) @@ -21,6 +21,7 @@ #ifndef GCC_MSP430_PROTOS_H #define GCC_MSP430_PROTOS_H +bool msp430_do_not_relax_short_jumps (void); rtx msp430_eh_return_stackadj_rtx (void); void msp430_expand_eh_return (rtx); void msp430_expand_epilogue (int); @@ -40,6 +41,7 @@ const char * msp430x_logical_shift_right (rtx); const char * msp430_mcu_name (void); bool msp430_modes_tieable_p (machine_mode, machine_mode); +void msp430_output_aligned_decl_common (FILE *, const tree, const char *, unsigned HOST_WIDE_INT, unsigned); void msp430_output_labelref (FILE *, const char *); void msp430_register_pragmas (void); rtx msp430_return_addr_rtx (int); Index: gcc/config/msp430/msp430.c =================================================================== --- gcc/config/msp430/msp430.c (revision 222796) +++ gcc/config/msp430/msp430.c (working copy) @@ -244,6 +244,11 @@ if (TARGET_LARGE && !msp430x) error ("-mlarge requires a 430X-compatible -mmcu="); + if (msp430_code_region == UPPER && ! msp430x) + error ("-mcode-region=upper requires 430X-compatible cpu"); + if (msp430_data_region == UPPER && ! msp430x) + error ("-mdata-region=upper requires 430X-compatible cpu"); + if (flag_exceptions || flag_non_call_exceptions || flag_unwind_tables || flag_asynchronous_unwind_tables) flag_omit_frame_pointer = false; @@ -1146,46 +1151,234 @@ + cfun->machine->framesize_outgoing); } +/* Attribute Handling. */ + +const char * const ATTR_INTR = "interrupt"; +const char * const ATTR_WAKEUP = "wakeup"; +const char * const ATTR_NAKED = "naked"; +const char * const ATTR_REENT = "reentrant"; +const char * const ATTR_CRIT = "critical"; +const char * const ATTR_LOWER = "lower"; +const char * const ATTR_UPPER = "upper"; +const char * const ATTR_EITHER = "either"; + static inline bool -is_attr_func (const char * attr) +has_attr (const char * attr, tree decl) { - return lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE; + if (decl == NULL_TREE) + return false; + return lookup_attribute (attr, DECL_ATTRIBUTES (decl)) != NULL_TREE; } +static bool +is_interrupt_func (tree decl = current_function_decl) +{ + return has_attr (ATTR_INTR, decl); +} + /* Returns true if the current function has the "interrupt" attribute. */ bool msp430_is_interrupt_func (void) { - if (current_function_decl == NULL) - return false; - return is_attr_func ("interrupt"); + return is_interrupt_func (current_function_decl); } static bool -is_wakeup_func (void) +is_wakeup_func (tree decl = current_function_decl) { - return msp430_is_interrupt_func () && is_attr_func ("wakeup"); + return is_interrupt_func (decl) && has_attr (ATTR_WAKEUP, decl); } static inline bool -is_naked_func (void) +is_naked_func (tree decl = current_function_decl) { - return is_attr_func ("naked"); + return has_attr (ATTR_NAKED, decl); } static inline bool -is_reentrant_func (void) +is_reentrant_func (tree decl = current_function_decl) { - return is_attr_func ("reentrant"); + return has_attr (ATTR_REENT, decl); } static inline bool -is_critical_func (void) +is_critical_func (tree decl = current_function_decl) { - return is_attr_func ("critical"); + return has_attr (ATTR_CRIT, decl); } +#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS msp430_allocate_stack_slots_for_args + +static bool +msp430_allocate_stack_slots_for_args (void) +{ + /* Naked functions should not allocate stack slots for arguments. */ + return ! is_naked_func (); +} + +/* Verify MSP430 specific attributes. */ +#define TREE_NAME_EQ(NAME, STR) (strcmp (IDENTIFIER_POINTER (NAME), (STR)) == 0) + +static tree +msp430_attr (tree * node, + tree name, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + + if (args != NULL) + { + gcc_assert (TREE_NAME_EQ (name, ATTR_INTR)); + + tree value = TREE_VALUE (args); + + switch (TREE_CODE (value)) + { + case STRING_CST: + if ( strcmp (TREE_STRING_POINTER (value), "reset") + && strcmp (TREE_STRING_POINTER (value), "nmi") + && strcmp (TREE_STRING_POINTER (value), "watchdog")) + /* Allow the attribute to be added - the linker script + being used may still recognise this name. */ + warning (OPT_Wattributes, + "unrecognised interrupt vector argument of %qE attribute", + name); + break; + + case INTEGER_CST: + 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, + "numeric argument of %qE attribute must be in range 0..63", + name); + break; + + default: + warning (OPT_Wattributes, + "argument of %qE attribute is not a string constant or number", + name); + *no_add_attrs = true; + break; + } + } + + const char * message = NULL; + + if (TREE_CODE (* node) != FUNCTION_DECL) + { + message = "%qE attribute only applies to functions"; + } + else if (TREE_NAME_EQ (name, ATTR_INTR)) + { + if (TREE_CODE (TREE_TYPE (* node)) == FUNCTION_TYPE + && ! VOID_TYPE_P (TREE_TYPE (TREE_TYPE (* node)))) + message = "interrupt handlers must be void"; + } + else if (TREE_NAME_EQ (name, ATTR_REENT)) + { + if (is_naked_func (* node)) + message = "naked functions cannot be reentrant"; + else if (is_critical_func (* node)) + message = "critical functions cannot be reentrant"; + } + else if (TREE_NAME_EQ (name, ATTR_CRIT)) + { + if (is_naked_func (* node)) + message = "naked functions cannot be critical"; + else if (is_reentrant_func (* node)) + message = "reentranct functions cannot be critical"; + } + else if (TREE_NAME_EQ (name, ATTR_NAKED)) + { + if (is_critical_func (* node)) + message = "critical functions cannot be naked"; + else if (is_reentrant_func (* node)) + message = "reentrant functions cannot be naked"; + } + + if (message) + { + warning (OPT_Wattributes, message, name); + * no_add_attrs = true; + } + + return NULL_TREE; +} + +static tree +msp430_section_attr (tree * node, + tree name, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs ATTRIBUTE_UNUSED) +{ + gcc_assert (DECL_P (* node)); + gcc_assert (args == NULL); + + const char * message = NULL; + + if (TREE_NAME_EQ (name, ATTR_UPPER)) + { + if (has_attr (ATTR_LOWER, * node)) + message = "already marked with 'lower' attribute"; + else if (has_attr (ATTR_EITHER, * node)) + message = "already marked with 'either' attribute"; + else if (! msp430x) + message = "upper attribute needs a 430X cpu"; + } + else if (TREE_NAME_EQ (name, ATTR_LOWER)) + { + if (has_attr (ATTR_UPPER, * node)) + message = "already marked with 'upper' attribute"; + else if (has_attr (ATTR_EITHER, * node)) + message = "already marked with 'either' attribute"; + } + else + { + gcc_assert (TREE_NAME_EQ (name, ATTR_EITHER)); + + if (has_attr (ATTR_LOWER, * node)) + message = "already marked with 'lower' attribute"; + else if (has_attr (ATTR_UPPER, * node)) + message = "already marked with 'upper' attribute"; + } + + if (message) + { + warning (OPT_Wattributes, message, name); + * no_add_attrs = true; + } + + return NULL_TREE; +} + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table + +/* Table of MSP430-specific attributes. */ +const struct attribute_spec msp430_attribute_table[] = +{ + /* Name min_num_args type_req, affects_type_identity + max_num_args, fn_type_req + decl_req handler. */ + { ATTR_INTR, 0, 1, true, false, false, msp430_attr, false }, + { ATTR_NAKED, 0, 0, true, false, false, msp430_attr, false }, + { ATTR_REENT, 0, 0, true, false, false, msp430_attr, false }, + { ATTR_CRIT, 0, 0, true, false, false, msp430_attr, false }, + { ATTR_WAKEUP, 0, 0, true, false, false, msp430_attr, false }, + + { ATTR_LOWER, 0, 0, true, false, false, msp430_section_attr, false }, + { ATTR_UPPER, 0, 0, true, false, false, msp430_section_attr, false }, + { ATTR_EITHER, 0, 0, true, false, false, msp430_section_attr, false }, + + { NULL, 0, 0, false, false, false, NULL, false } +}; + #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function @@ -1260,85 +1453,6 @@ } } -/* Verify MSP430 specific attributes. */ - -static tree -msp430_attr (tree * node, - tree name, - tree args, - int flags ATTRIBUTE_UNUSED, - bool * no_add_attrs) -{ - gcc_assert (DECL_P (* node)); - - if (args != NULL) - { - tree value = TREE_VALUE (args); - - switch (TREE_CODE (value)) - { - case STRING_CST: - if ( strcmp (TREE_STRING_POINTER (value), "reset") - && strcmp (TREE_STRING_POINTER (value), "nmi") - && strcmp (TREE_STRING_POINTER (value), "watchdog")) - /* Allow the attribute to be added - the linker script - being used may still recognise this name. */ - warning (OPT_Wattributes, - "unrecognised interrupt vector argument of %qE attribute", - name); - break; - - case INTEGER_CST: - 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, - "numeric argument of %qE attribute must be in range 0..63", - name); - break; - - default: - warning (OPT_Wattributes, - "argument of %qE attribute is not a string constant or number", - name); - *no_add_attrs = true; - break; - } - } - - if (TREE_CODE (* node) != FUNCTION_DECL) - { - warning (OPT_Wattributes, - "%qE attribute only applies to functions", - name); - * no_add_attrs = true; - } - - /* FIXME: We ought to check that the interrupt handler - attribute has been applied to a void function. */ - /* FIXME: We should check that reentrant and critical - functions are not naked and that critical functions - are not reentrant. */ - - return NULL_TREE; -} - -#undef TARGET_ATTRIBUTE_TABLE -#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table - -/* Table of MSP430-specific attributes. */ -const struct attribute_spec msp430_attribute_table[] = -{ - /* Name min_len decl_req, fn_type_req, affects_type_identity - max_len, type_req, handler. */ - { "interrupt", 0, 1, true, false, false, msp430_attr, false }, - { "naked", 0, 0, true, false, false, msp430_attr, false }, - { "reentrant", 0, 0, true, false, false, msp430_attr, false }, - { "critical", 0, 0, true, false, false, msp430_attr, false }, - { "wakeup", 0, 0, true, false, false, msp430_attr, false }, - { NULL, 0, 0, false, false, false, NULL, false } -}; - void msp430_start_function (FILE *file, const char *name, tree decl) { @@ -1378,22 +1492,254 @@ ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); } +static const char * const lower_prefix = ".lower"; +static const char * const upper_prefix = ".upper"; +static const char * const either_prefix = ".either"; + +/* Generate a prefix for a section name, based upon + the region into which the object should be placed. */ + +static const char * +gen_prefix (tree decl) +{ + if (DECL_ONE_ONLY (decl)) + return NULL; + + /* If the user has specified a particular section then do not use any prefix. */ + if (has_attr ("section", decl)) + return NULL; + + /* If the object has __attribute__((lower)) then use the ".lower." prefix. */ + 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; + + if (has_attr (ATTR_EITHER, decl)) + return either_prefix; + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (msp430_code_region == LOWER) + return lower_prefix; + + if (msp430_code_region == UPPER) + return upper_prefix; + + if (msp430_code_region == EITHER) + return either_prefix; + } + else + { + if (msp430_data_region == LOWER) + return lower_prefix; + + if (msp430_data_region == UPPER) + return upper_prefix; + + if (msp430_data_region == EITHER) + return either_prefix; + } + + return NULL; +} + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION msp430_select_section + static section * -msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit) +msp430_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { + gcc_assert (decl != NULL_TREE); + + if (TREE_CODE (decl) == STRING_CST + || TREE_CODE (decl) == CONSTRUCTOR + || TREE_CODE (decl) == INTEGER_CST + || TREE_CODE (decl) == VECTOR_CST + || TREE_CODE (decl) == COMPLEX_CST) + return default_select_section (decl, reloc, align); + /* In large mode we must make sure that interrupt handlers are put into low memory as the vector table only accepts 16-bit addresses. */ - if (TARGET_LARGE - && lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl))) + if (TARGET_LARGE && TREE_CODE (decl) == FUNCTION_DECL && is_interrupt_func (decl)) return get_section (".lowtext", SECTION_CODE | SECTION_WRITE , decl); - /* Otherwise, use the default function section. */ - return default_function_section (decl, freq, startup, exit); + const char * prefix = gen_prefix (decl); + if (prefix == NULL) + { + if (TREE_CODE (decl) == FUNCTION_DECL) + return text_section; + else + return default_select_section (decl, reloc, align); + } + + const char * sec; + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_TEXT: sec = ".text"; break; + case SECCAT_DATA: sec = ".data"; break; + case SECCAT_BSS: sec = ".bss"; break; + case SECCAT_RODATA: sec = ".rodata"; break; + + case SECCAT_RODATA_MERGE_STR: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_CONST: + case SECCAT_SRODATA: + case SECCAT_DATA_REL: + case SECCAT_DATA_REL_LOCAL: + case SECCAT_DATA_REL_RO: + case SECCAT_DATA_REL_RO_LOCAL: + case SECCAT_SDATA: + case SECCAT_SBSS: + case SECCAT_TDATA: + case SECCAT_TBSS: + return default_select_section (decl, reloc, align); + + default: + gcc_unreachable (); + } + + const char * dec_name = DECL_SECTION_NAME (decl); + char * name = ACONCAT ((prefix, sec, dec_name, NULL)); + + return get_named_section (decl, name, 0); } #undef TARGET_ASM_FUNCTION_SECTION #define TARGET_ASM_FUNCTION_SECTION msp430_function_section +static section * +msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit) +{ + const char * name; + + gcc_assert (DECL_SECTION_NAME (decl) != NULL); + name = DECL_SECTION_NAME (decl); + + const char * prefix = gen_prefix (decl); + if (prefix == NULL + || strncmp (name, prefix, strlen (prefix)) == 0) + return default_function_section (decl, freq, startup, exit); + + name = ACONCAT ((prefix, name, NULL)); + return get_named_section (decl, name, 0); +} + +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS msp430_section_type_flags + +unsigned int +msp430_section_type_flags (tree decl, const char * name, int reloc) +{ + if (strncmp (name, lower_prefix, strlen (lower_prefix)) == 0) + name += strlen (lower_prefix); + else if (strncmp (name, upper_prefix, strlen (upper_prefix)) == 0) + name += strlen (upper_prefix); + else if (strncmp (name, either_prefix, strlen (either_prefix)) == 0) + name += strlen (either_prefix); + + return default_section_type_flags (decl, name, reloc); +} + +#undef TARGET_ASM_UNIQUE_SECTION +#define TARGET_ASM_UNIQUE_SECTION msp430_unique_section + +static void +msp430_unique_section (tree decl, int reloc) +{ + gcc_assert (decl != NULL_TREE); + + /* In large mode we must make sure that interrupt handlers are put into + low memory as the vector table only accepts 16-bit addresses. */ + if (TARGET_LARGE && TREE_CODE (decl) == FUNCTION_DECL && is_interrupt_func (decl)) + { + set_decl_section_name (decl, ".lowtext"); + return; + } + + default_unique_section (decl, reloc); + + const char * prefix; + + if ( TREE_CODE (decl) == STRING_CST + || TREE_CODE (decl) == CONSTRUCTOR + || TREE_CODE (decl) == INTEGER_CST + || TREE_CODE (decl) == VECTOR_CST + || TREE_CODE (decl) == COMPLEX_CST + || (prefix = gen_prefix (decl)) == NULL + ) + return; + + const char * dec_name = DECL_SECTION_NAME (decl); + char * name = ACONCAT ((prefix, dec_name, NULL)); + + set_decl_section_name (decl, name); +} + +/* 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, + const char * name, + unsigned HOST_WIDE_INT size, + unsigned int align) +{ + if (msp430_data_region == ANY) + { + fprintf (stream, COMMON_ASM_OP); + assemble_name (stream, name); + fprintf (stream, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", + size, align / BITS_PER_UNIT); + } + else + { + section * sec; + + if (decl) + sec = msp430_select_section (decl, 0, align); + else + switch (msp430_data_region) + { + case UPPER: sec = get_named_section (NULL, ".upper.bss", 0); break; + case LOWER: sec = get_named_section (NULL, ".lower.bss", 0); break; + case EITHER: sec = get_named_section (NULL, ".either.bss", 0); break; + default: + gcc_unreachable (); + } + gcc_assert (sec != NULL); + + switch_to_section (sec); + ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT)); + targetm.asm_out.globalize_label (stream, name); + ASM_WEAKEN_LABEL (stream, name); + ASM_OUTPUT_LABEL (stream, name); + ASM_OUTPUT_SKIP (stream, size ? size : 1); + } +} + +bool +msp430_do_not_relax_short_jumps (void) +{ + /* When placing code into "either" low or high memory we do not want the linker + to grow the size of sections, which it can do if it is encounters a branch to + a label that is too far away. So we tell the cbranch patterns to avoid using + short jumps when there is a chance that the instructions will end up in a low + section. */ + return + msp430_code_region == EITHER + || msp430_code_region == LOWER + || has_attr (ATTR_EITHER, current_function_decl) + || has_attr (ATTR_LOWER, current_function_decl); +} + enum msp430_builtin { MSP430_BUILTIN_BIC_SR, Index: gcc/config/msp430/msp430.h =================================================================== --- gcc/config/msp430/msp430.h (revision 222796) +++ gcc/config/msp430/msp430.h (working copy) @@ -404,3 +404,9 @@ msp430_start_function ((FILE), (NAME), (DECL)) #define TARGET_HAS_NO_HW_DIVIDE (! TARGET_HWMULT) + +#undef USE_SELECT_SECTION_FOR_FUNCTIONS +#define USE_SELECT_SECTION_FOR_FUNCTIONS 1 + +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \ + msp430_output_aligned_decl_common ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) Index: gcc/config/msp430/msp430.md =================================================================== --- gcc/config/msp430/msp430.md (revision 222796) +++ gcc/config/msp430/msp430.md (working copy) @@ -58,6 +58,9 @@ UNS_DELAY_END ]) +;; This is an approximation. +(define_attr "length" "" (const_int 4)) + (include "predicates.md") (include "constraints.md") @@ -210,7 +213,7 @@ "" "" ) - + (define_insn_and_split "movsi_x" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (match_operand:SI 1 "general_operand" "rmi"))] @@ -551,7 +554,7 @@ [(set (match_dup 0) (zero_extend:HI (match_dup 1)))] ) - + (define_insn "zero_extendhipsi2" [(set (match_operand:PSI 0 "msp_nonimmediate_operand" "=r,m") (zero_extend:PSI (match_operand:HI 1 "msp_nonimmediate_operand" "rm,r")))] @@ -939,7 +942,6 @@ "msp430_expand_epilogue (0); DONE;" ) - (define_insn "epilogue_helper" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)] "" @@ -946,7 +948,6 @@ "BR%Q0\t#__mspabi_func_epilog_%J0" ) - (define_insn "prologue_start_marker" [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] "" @@ -1110,9 +1111,32 @@ (clobber (reg:BI CARRY)) ] "" - "@ - CMP.W\t%2, %1 { J%0\t%l3 - CMP%X0.W\t%2, %1 { J%0\t%l3" + "* + /* This is nasty. If we are splitting code between low and high memory + then we do not want the linker to increase the size of sections by + relaxing out of range jump instructions. (Since relaxation occurs + after section placement). So we have to generate pessimal branches + here. But we only want to do this when really necessary. + + FIXME: Do we need code in the other cbranch patterns ? */ + if (msp430_do_not_relax_short_jumps () && get_attr_length (insn) > 6) + { + 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:\"; + } + + return which_alternative == 0 ? + \"CMP.W\t%2, %1 { J%0\t%l3\" : + \"CMP%X0.W\t%2, %1 { J%0\t%l3\"; + " + [(set (attr "length") + (if_then_else + (and (ge (minus (match_dup 3) (pc)) (const_int -510)) + (le (minus (match_dup 3) (pc)) (const_int 510))) + (const_int 6) + (const_int 10)) + )] ) (define_insn "cbranchpsi4_reversed" Index: gcc/config/msp430/msp430.opt =================================================================== --- gcc/config/msp430/msp430.opt (revision 222796) +++ gcc/config/msp430/msp430.opt (working copy) @@ -57,3 +57,26 @@ EnumValue Enum(msp430_hwmult_types) String(f5series) Value(F5SERIES) + +mcode-region= +Target Joined RejectNegative Report ToLower Var(msp430_code_region) Enum(msp430_regions) Init(ANY) +Specify whether functions should be placed into low or high memory + +mdata-region= +Target Joined RejectNegative Report ToLower Var(msp430_data_region) Enum(msp430_regions) Init(ANY) +Specify whether variables should be placed into low or high memory + +Enum +Name(msp430_regions) Type(enum msp430_regions) + +EnumValue +Enum(msp430_regions) String(none) Value(ANY) + +EnumValue +Enum(msp430_regions) String(either) Value(EITHER) + +EnumValue +Enum(msp430_regions) String(lower) Value(LOWER) + +EnumValue +Enum(msp430_regions) String(upper) Value(UPPER) Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 222796) +++ gcc/doc/extend.texi (working copy) @@ -3254,6 +3254,38 @@ At present, a declaration to which @code{weakref} is attached can only be @code{static}. +@item lower +@itemx upper +@itemx either +@cindex lower memory region on the MSP430 +@cindex upper memory region on the MSP430 +@cindex either memory region on the MSP430 +On the MSP430 target these attributes can be used to specify whether +the function or variable should be placed into low memory, high +memory, or the placement should be left to the linker to decide. The +attributes are only significant if compiling for the MSP430X +architecture. + +The attributes work in conjunction with a linker script that has been +augmented to specify where to place sections with a @code{.lower} and +a @code{.upper} prefix. So for example as well as placing the +@code{.data} section the script would also specify the placement of a +@code{.lower.data} and a @code{.upper.data} section. The intention +being that @code{lower} sections are placed into a small but easier to +access memory region and the upper sections are placed into a larger, but +slower to access region. + +The @code{either} attribute is special. It tells the linker to place +the object into the corresponding @code{lower} section if there is +room for it. If there is insufficient room then the object is placed +into the corresponding @code{upper} section instead. Note - the +placement algorithm is not very sophisticated. It will not attempt to +find an optimal packing of the @code{lower} sections. It just makes +one pass over the objects and does the best that it can. Using the +@option{-ffunction-sections} and @option{-fdata-sections} command line +options can help the packing however, since they produce smaller, +easier to pack regions. + @end table @c This is the end of the target-independent attribute table Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 222796) +++ gcc/doc/invoke.texi (working copy) @@ -826,6 +826,7 @@ @emph{MSP430 Options} @gccoptlist{-msim -masm-hex -mmcu= -mcpu= -mlarge -msmall -mrelax @gol +-mcode-region= -mdata-region= @gol -mhwmult= -minrt} @emph{NDS32 Options} @@ -18155,6 +18156,19 @@ devices. The compiler includes special symbols in some objects that tell the linker and runtime which code fragments are required. +@item -mcode-region= +@itemx -mdata-region= +@opindex mcode-region +@opindex mdata-region +These options tell the compiler where to place functions and data that +do not have one of the @code{lower}, @code{upper}, @code{either} or +@code{section} attributes. Possible values are @code{lower}, +@code{upper}, @code{either} or @code{any}. The first three behave +like the corresponding attribute. The fourth possible value - +@code{any} - is the default. It leaves placement entirely up to the +linker script and how it assigns the standard sections (.text, .data +etc) to the memory regions. + @end table @node NDS32 Options --=-=-=--