msp430-opts.h (enum msp430_regions): New.
* 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. From-SVN: r222810
This commit is contained in:
parent
c87b25e697
commit
d7edde11e0
9 changed files with 594 additions and 105 deletions
|
@ -1,3 +1,37 @@
|
|||
2015-05-05 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* 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 <matthew.wahab@arm.com>
|
||||
|
||||
* gcc/config/aarch64-protos.h (struct cpu_branch_cost): New.
|
||||
|
|
|
@ -29,4 +29,12 @@ enum msp430_hwmult_types
|
|||
F5SERIES
|
||||
};
|
||||
|
||||
enum msp430_regions
|
||||
{
|
||||
ANY,
|
||||
EITHER,
|
||||
LOWER,
|
||||
UPPER
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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. */
|
||||
|
@ -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 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 @@ 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 section *
|
||||
msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit)
|
||||
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_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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue