From ab9c90cd1d82c9b730d3a57bfecf8e1153810b7f Mon Sep 17 00:00:00 2001 From: nickc Date: Tue, 5 May 2015 15:15:13 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222810 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 34 +++ gcc/config/msp430/msp430-opts.h | 8 + gcc/config/msp430/msp430-protos.h | 2 + gcc/config/msp430/msp430.c | 540 +++++++++++++++++++++++++++++++------- gcc/config/msp430/msp430.h | 6 + gcc/config/msp430/msp430.md | 38 ++- gcc/config/msp430/msp430.opt | 23 ++ gcc/doc/extend.texi | 32 +++ gcc/doc/invoke.texi | 14 + 9 files changed, 593 insertions(+), 104 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5f3c8b64205..d8d673c6c6d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +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. + 2015-05-05 Matthew Wahab * gcc/config/aarch64-protos.h (struct cpu_branch_cost): New. diff --git a/gcc/config/msp430/msp430-opts.h b/gcc/config/msp430/msp430-opts.h index ad3ca6d5d2c..258dccbd29c 100644 --- a/gcc/config/msp430/msp430-opts.h +++ b/gcc/config/msp430/msp430-opts.h @@ -29,4 +29,12 @@ enum msp430_hwmult_types F5SERIES }; +enum msp430_regions +{ + ANY, + EITHER, + LOWER, + UPPER +}; + #endif diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index 6246a64a5dc..b4fd58721f3 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -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 @@ bool msp430_is_interrupt_func (void); 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); diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index e3c608be530..3658dfcc89a 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -244,6 +244,11 @@ msp430_option_override (void) 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,10 +1151,29 @@ msp430_compute_frame_info (void) + 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) +{ + 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 lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE; + return has_attr (ATTR_INTR, decl); } /* Returns true if the current function has the "interrupt" attribute. */ @@ -1157,35 +1181,204 @@ is_attr_func (const char * attr) 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 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) { - return is_attr_func ("critical"); + 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 @@ increment_stack (HOST_WIDE_INT amount) } } -/* 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 @@ msp430_start_function (FILE *file, const char *name, tree decl) 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, diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 68b20090f51..73e95727422 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -404,3 +404,9 @@ typedef struct 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)) diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index 0110ed8ac1a..91742fc38b5 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -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,14 +942,12 @@ "msp430_expand_epilogue (0); DONE;" ) - (define_insn "epilogue_helper" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)] "" "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" diff --git a/gcc/config/msp430/msp430.opt b/gcc/config/msp430/msp430.opt index 8215013e846..3fed8799822 100644 --- a/gcc/config/msp430/msp430.opt +++ b/gcc/config/msp430/msp430.opt @@ -57,3 +57,26 @@ Enum(msp430_hwmult_types) String(32bit) Value(LARGE) 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) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 4ae301ff235..a5047959113 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3254,6 +3254,38 @@ performing a reloadable link on them. 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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 324e517117f..debd8eddda0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -827,6 +827,7 @@ Objective-C and Objective-C++ Dialects}. @emph{MSP430 Options} @gccoptlist{-msim -masm-hex -mmcu= -mcpu= -mlarge -msmall -mrelax @gol +-mcode-region= -mdata-region= @gol -mhwmult= -minrt} @emph{NDS32 Options} @@ -18164,6 +18165,19 @@ initializers or constructors. This is intended for memory-constrained 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 -- 2.11.4.GIT