public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Commit: MSP430: Add -mcode-region= and -mdata-region= options
@ 2015-05-05 15:14 Nick Clifton
  0 siblings, 0 replies; only message in thread
From: Nick Clifton @ 2015-05-05 15:14 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2384 bytes --]

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

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: msp430.memory-regions.patch --]
[-- Type: text/x-patch, Size: 26769 bytes --]

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-05-05 15:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-05 15:14 Commit: MSP430: Add -mcode-region= and -mdata-region= options Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).