/* Subroutines used for code generation on TI MSP430 processors.
- Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ Copyright (C) 2012-2019 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GCC.
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#define IN_TARGET_CODE 1
+
#include "config.h"
#include "system.h"
#include "coretypes.h"
if (target_mcu)
{
unsigned int i;
- static char mcu_name [64];
+ unsigned int start_upper;
+ unsigned int end_upper;
+ static char mcu_name[64];
- snprintf (mcu_name, sizeof (mcu_name) - 1, "__%s__", target_mcu);
- for (i = strlen (mcu_name); i--;)
+ /* The 'i' in the device name symbol for msp430i* devices must be lower
+ case, to match the expected symbol in msp430.h. */
+ if (strncmp (target_mcu, "msp430i", 7) == 0)
+ {
+ snprintf (mcu_name, sizeof (mcu_name) - 1, "__MSP430i%s__",
+ target_mcu + 7);
+ start_upper = 9;
+ }
+ else
+ {
+ snprintf (mcu_name, sizeof (mcu_name) - 1, "__%s__", target_mcu);
+ start_upper = 2;
+ }
+ end_upper = strlen (mcu_name) - 2;
+ for (i = start_upper; i < end_upper; i++)
mcu_name[i] = TOUPPER (mcu_name[i]);
return mcu_name;
}
static void
msp430_option_override (void)
{
+ /* The MSP430 architecture can safely dereference a NULL pointer. In fact,
+ there are memory mapped registers there. */
+ flag_delete_null_pointer_checks = 0;
+
init_machine_status = msp430_init_machine_status;
if (target_cpu)
if (msp430_warn_mcu)
{
if (target_cpu&& msp430x != xisa)
- warning (0, "MCU '%s' supports %s ISA but -mcpu option is set to %s",
+ warning (0, "MCU '%s' supports %s ISA but %<-mcpu%> option "
+ "is set to %s",
target_mcu, xisa ? "430X" : "430", msp430x ? "430X" : "430");
if (msp430_mcu_data[i].hwmpy == 0
&& msp430_hwmult_type != MSP430_HWMULT_AUTO
&& msp430_hwmult_type != MSP430_HWMULT_NONE)
- warning (0, "MCU '%s' does not have hardware multiply support, but -mhwmult is set to %s",
+ warning (0, "MCU '%s' does not have hardware multiply "
+ "support, but %<-mhwmult%> is set to %s",
target_mcu,
msp430_hwmult_type == MSP430_HWMULT_SMALL ? "16-bit"
: msp430_hwmult_type == MSP430_HWMULT_LARGE ? "32-bit" : "f5series");
else if (msp430_hwmult_type == MSP430_HWMULT_SMALL
&& msp430_mcu_data[i].hwmpy != 1
&& msp430_mcu_data[i].hwmpy != 2 )
- warning (0, "MCU '%s' supports %s hardware multiply, but -mhwmult is set to 16-bit",
+ warning (0, "MCU '%s' supports %s hardware multiply, "
+ "but %<-mhwmult%> is set to 16-bit",
target_mcu, hwmult_name (msp430_mcu_data[i].hwmpy));
else if (msp430_hwmult_type == MSP430_HWMULT_LARGE && msp430_mcu_data[i].hwmpy != 4)
- warning (0, "MCU '%s' supports %s hardware multiply, but -mhwmult is set to 32-bit",
+ warning (0, "MCU '%s' supports %s hardware multiply, "
+ "but %<-mhwmult%> is set to 32-bit",
target_mcu, hwmult_name (msp430_mcu_data[i].hwmpy));
else if (msp430_hwmult_type == MSP430_HWMULT_F5SERIES && msp430_mcu_data[i].hwmpy != 8)
- warning (0, "MCU '%s' supports %s hardware multiply, but -mhwmult is set to f5series",
+ warning (0, "MCU '%s' supports %s hardware multiply, "
+ "but %<-mhwmult%> is set to f5series",
target_mcu, hwmult_name (msp430_mcu_data[i].hwmpy));
}
warning (0,
"Unrecognized MCU name '%s', assuming that it is "
"just a MSP430 with no hardware multiply.\n"
- "Use the -mcpu and -mhwmult options to set "
- "these explicitly.",
+ "Use the %<-mcpu%> and %<-mhwmult%> options to "
+ "set these explicitly.",
target_mcu);
else
warning (0,
"Unrecognized MCU name '%s', assuming that it "
- "has no hardware multiply.\nUse the -mhwmult "
+ "has no hardware multiply.\nUse the %<-mhwmult%> "
"option to set this explicitly.",
target_mcu);
}
if (msp430_warn_mcu)
warning (0,
"Unrecognized MCU name '%s', assuming that it just "
- "supports the MSP430 ISA.\nUse the -mcpu option to "
- "set the ISA explicitly.",
+ "supports the MSP430 ISA.\nUse the %<-mcpu%> option "
+ "to set the ISA explicitly.",
target_mcu);
msp430x = false;
msp430x = true;
if (TARGET_LARGE && !msp430x)
- error ("-mlarge requires a 430X-compatible -mmcu=");
+ error ("%<-mlarge%> requires a 430X-compatible %<-mmcu=%>");
if (msp430_code_region == MSP430_REGION_UPPER && ! msp430x)
- error ("-mcode-region=upper requires 430X-compatible cpu");
+ error ("%<-mcode-region=upper%> requires 430X-compatible cpu");
if (msp430_data_region == MSP430_REGION_UPPER && ! msp430x)
- error ("-mdata-region=upper requires 430X-compatible cpu");
+ error ("%<-mdata-region=upper%> requires 430X-compatible cpu");
if (flag_exceptions || flag_non_call_exceptions
|| flag_unwind_tables || flag_asynchronous_unwind_tables)
{
if (mode == PSImode && msp430x)
return 1;
+ if (mode == CPSImode && msp430x)
+ return 2;
return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
/ UNITS_PER_WORD);
}
{
if (mode == PSImode)
return 2;
+ if (mode == CPSImode)
+ return 4;
return msp430_hard_regno_nregs (regno, mode);
}
#undef TARGET_GET_RAW_ARG_MODE
#define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode
-static machine_mode
+static fixed_size_mode
msp430_get_raw_arg_mode (int regno)
{
- return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
+ return as_a <fixed_size_mode> (regno == ARG_POINTER_REGNUM
+ ? VOIDmode : Pmode);
}
#undef TARGET_GET_RAW_RESULT_MODE
#define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode
-static machine_mode
+static fixed_size_mode
msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED)
{
return Pmode;
return ! is_naked_func ();
}
+#undef TARGET_WARN_FUNC_RETURN
+#define TARGET_WARN_FUNC_RETURN msp430_warn_func_return
+
+static bool
+msp430_warn_func_return (tree decl)
+{
+ /* Naked functions are implemented entirely in assembly, including the
+ return sequence, so suppress warnings about this. */
+ return !is_naked_func (decl);
+}
+
/* Verify MSP430 specific attributes. */
#define TREE_NAME_EQ(NAME, STR) (strcmp (IDENTIFIER_POINTER (NAME), (STR)) == 0)
{
gcc_assert (DECL_P (* node));
+ /* Only the interrupt attribute takes an argument. */
if (args != NULL)
{
- /* Only the interrupt attribute takes an argument. */
- gcc_assert (TREE_NAME_EQ (name, ATTR_INTR));
-
tree value = TREE_VALUE (args);
switch (TREE_CODE (value))
break;
case INTEGER_CST:
- if (wi::gtu_p (value, 63))
+ if (wi::gtu_p (wi::to_wide (value), 63))
/* Allow the attribute to be added - the linker script
being used may still recognise this value. */
warning (OPT_Wattributes,
if (TREE_CODE (TREE_TYPE (* node)) == FUNCTION_TYPE
&& ! VOID_TYPE_P (TREE_TYPE (TREE_TYPE (* node))))
message = "interrupt handlers must be void";
-
- if (! TREE_PUBLIC (* node))
- message = "interrupt handlers cannot be static";
-
- /* Ensure interrupt handlers never get optimised out. */
- TREE_USED (* node) = 1;
- DECL_PRESERVE_P (* node) = 1;
+ else
+ {
+ /* Ensure interrupt handlers never get optimised out. */
+ TREE_USED (* node) = 1;
+ DECL_PRESERVE_P (* node) = 1;
+ }
+ if (is_critical_func (* node))
+ {
+ warning (OPT_Wattributes,
+ "critical attribute has no effect on interrupt functions");
+ DECL_ATTRIBUTES (*node) = remove_attribute (ATTR_CRIT,
+ DECL_ATTRIBUTES (* node));
+ }
}
else if (TREE_NAME_EQ (name, ATTR_REENT))
{
message = "naked functions cannot be critical";
else if (is_reentrant_func (* node))
message = "reentrant functions cannot be critical";
+ else if (is_interrupt_func ( *node))
+ message = "critical attribute has no effect on interrupt functions";
}
else if (TREE_NAME_EQ (name, ATTR_NAKED))
{
/* 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 },
-
- { ATTR_NOINIT, 0, 0, true, false, false, msp430_data_attr, false },
- { ATTR_PERSIST, 0, 0, true, false, false, msp430_data_attr, false },
-
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* Name min_num_args type_req, handler
+ max_num_args, fn_type_req exclude
+ decl_req affects_type_identity. */
+ { ATTR_INTR, 0, 1, true, false, false, false, msp430_attr, NULL },
+ { ATTR_NAKED, 0, 0, true, false, false, false, msp430_attr, NULL },
+ { ATTR_REENT, 0, 0, true, false, false, false, msp430_attr, NULL },
+ { ATTR_CRIT, 0, 0, true, false, false, false, msp430_attr, NULL },
+ { ATTR_WAKEUP, 0, 0, true, false, false, false, msp430_attr, NULL },
+
+ { ATTR_LOWER, 0, 0, true, false, false, false, msp430_section_attr,
+ NULL },
+ { ATTR_UPPER, 0, 0, true, false, false, false, msp430_section_attr,
+ NULL },
+ { ATTR_EITHER, 0, 0, true, false, false, false, msp430_section_attr,
+ NULL },
+
+ { ATTR_NOINIT, 0, 0, true, false, false, false, msp430_data_attr,
+ NULL },
+ { ATTR_PERSIST, 0, 0, true, false, false, false, msp430_data_attr,
+ NULL },
+
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
#undef TARGET_ASM_FUNCTION_PROLOGUE
}
}
+ if (user_label_prefix[0] != 0)
+ fputs (user_label_prefix, file);
+
fputs (name, file);
}
}
}
+#undef TARGET_ASM_ALIGNED_PSI_OP
+#define TARGET_ASM_ALIGNED_PSI_OP "\t.long\t"
+#undef TARGET_ASM_UNALIGNED_PSI_OP
+#define TARGET_ASM_UNALIGNED_PSI_OP TARGET_ASM_ALIGNED_PSI_OP
+
#undef TARGET_PRINT_OPERAND_ADDRESS
#define TARGET_PRINT_OPERAND_ADDRESS msp430_print_operand_addr
return true;
}
\f
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-msp430.h"