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:
Nick Clifton 2015-05-05 15:15:13 +00:00 committed by Nick Clifton
parent c87b25e697
commit d7edde11e0
9 changed files with 594 additions and 105 deletions

View file

@ -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.

View file

@ -29,4 +29,12 @@ enum msp430_hwmult_types
F5SERIES
};
enum msp430_regions
{
ANY,
EITHER,
LOWER,
UPPER
};
#endif

View file

@ -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);

View file

@ -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,

View file

@ -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))

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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