aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/mep/mep-pragma.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/mep/mep-pragma.c')
-rw-r--r--gcc-4.9/gcc/config/mep/mep-pragma.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/mep/mep-pragma.c b/gcc-4.9/gcc/config/mep/mep-pragma.c
new file mode 100644
index 000000000..632e92da1
--- /dev/null
+++ b/gcc-4.9/gcc/config/mep/mep-pragma.c
@@ -0,0 +1,404 @@
+/* Definitions of Toshiba Media Processor
+ Copyright (C) 2001-2014 Free Software Foundation, Inc.
+ Contributed by Red Hat, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "diagnostic-core.h"
+#include "c-family/c-pragma.h"
+#include "cpplib.h"
+#include "hard-reg-set.h"
+#include "output.h" /* for decode_reg_name */
+#include "mep-protos.h"
+#include "function.h"
+#define MAX_RECOG_OPERANDS 10
+#include "reload.h"
+#include "target.h"
+
+enum cw_which { CW_AVAILABLE, CW_CALL_SAVED };
+
+/* This is normally provided by rtl.h but we can't include that file
+ here. It's safe to copy the definition here because we're only
+ using it internally; the value isn't passed to functions outside
+ this file. */
+#ifndef INVALID_REGNUM
+#define INVALID_REGNUM (~(unsigned int) 0)
+#endif
+
+static enum cpp_ttype
+mep_pragma_lex (tree *valp)
+{
+ enum cpp_ttype t = pragma_lex (valp);
+ if (t == CPP_EOF)
+ t = CPP_PRAGMA_EOL;
+ return t;
+}
+
+static void
+mep_pragma_io_volatile (cpp_reader *reader ATTRIBUTE_UNUSED)
+{
+ /* On off. */
+ tree val;
+ enum cpp_ttype type;
+ const char * str;
+
+ type = mep_pragma_lex (&val);
+ if (type == CPP_NAME)
+ {
+ str = IDENTIFIER_POINTER (val);
+
+ type = mep_pragma_lex (&val);
+ if (type != CPP_PRAGMA_EOL)
+ warning (0, "junk at end of #pragma io_volatile");
+
+ if (strcmp (str, "on") == 0)
+ {
+ target_flags |= MASK_IO_VOLATILE;
+ return;
+ }
+ if (strcmp (str, "off") == 0)
+ {
+ target_flags &= ~ MASK_IO_VOLATILE;
+ return;
+ }
+ }
+
+ error ("#pragma io_volatile takes only on or off");
+}
+
+static unsigned int
+parse_cr_reg (const char * str)
+{
+ unsigned int regno;
+
+ regno = decode_reg_name (str);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ return INVALID_REGNUM;
+
+ /* Verify that the regno is in CR_REGS. */
+ if (! TEST_HARD_REG_BIT (reg_class_contents[CR_REGS], regno))
+ return INVALID_REGNUM;
+ return regno;
+}
+
+static bool
+parse_cr_set (HARD_REG_SET * set)
+{
+ tree val;
+ enum cpp_ttype type;
+ unsigned int last_regno = INVALID_REGNUM;
+ bool do_range = false;
+
+ CLEAR_HARD_REG_SET (*set);
+
+ while ((type = mep_pragma_lex (&val)) != CPP_PRAGMA_EOL)
+ {
+ if (type == CPP_COMMA)
+ {
+ last_regno = INVALID_REGNUM;
+ do_range = false;
+ }
+ else if (type == CPP_ELLIPSIS)
+ {
+ if (last_regno == INVALID_REGNUM)
+ {
+ error ("invalid coprocessor register range");
+ return false;
+ }
+ do_range = true;
+ }
+ else if (type == CPP_NAME || type == CPP_STRING)
+ {
+ const char *str;
+ unsigned int regno, i;
+
+ if (TREE_CODE (val) == IDENTIFIER_NODE)
+ str = IDENTIFIER_POINTER (val);
+ else if (TREE_CODE (val) == STRING_CST)
+ str = TREE_STRING_POINTER (val);
+ else
+ gcc_unreachable ();
+
+ regno = parse_cr_reg (str);
+ if (regno == INVALID_REGNUM)
+ {
+ error ("invalid coprocessor register %qE", val);
+ return false;
+ }
+
+ if (do_range)
+ {
+ if (last_regno > regno)
+ i = regno, regno = last_regno;
+ else
+ i = last_regno;
+ do_range = false;
+ }
+ else
+ last_regno = i = regno;
+
+ while (i <= regno)
+ {
+ SET_HARD_REG_BIT (*set, i);
+ i++;
+ }
+ }
+ else
+ {
+ error ("malformed coprocessor register");
+ return false;
+ }
+ }
+ return true;
+}
+
+static void
+mep_pragma_coprocessor_which (enum cw_which cw_which)
+{
+ HARD_REG_SET set;
+
+ /* Process the balance of the pragma and turn it into a hard reg set. */
+ if (! parse_cr_set (&set))
+ return;
+
+ /* Process the collected hard reg set. */
+ switch (cw_which)
+ {
+ case CW_AVAILABLE:
+ {
+ int i;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (TEST_HARD_REG_BIT (set, i))
+ fixed_regs[i] = 0;
+ }
+ break;
+
+ case CW_CALL_SAVED:
+ {
+ int i;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (TEST_HARD_REG_BIT (set, i))
+ fixed_regs[i] = call_used_regs[i] = 0;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Fix up register class hierarchy. */
+ mep_save_register_info ();
+ mep_reinit_regs ();
+
+ if (cfun == 0)
+ {
+ init_dummy_function_start ();
+ init_caller_save ();
+ expand_dummy_function_end ();
+ }
+ else
+ {
+ init_caller_save ();
+ }
+}
+
+static void
+mep_pragma_coprocessor_width (void)
+{
+ tree val;
+ enum cpp_ttype type;
+ HOST_WIDE_INT i;
+
+ type = mep_pragma_lex (&val);
+ switch (type)
+ {
+ case CPP_NUMBER:
+ if (! tree_fits_uhwi_p (val))
+ break;
+ i = tree_to_uhwi (val);
+ /* This pragma no longer has any effect. */
+#if 0
+ if (i == 32)
+ target_flags &= ~MASK_64BIT_CR_REGS;
+ else if (i == 64)
+ target_flags |= MASK_64BIT_CR_REGS;
+ else
+ break;
+ targetm.init_builtins ();
+#else
+ if (i != 32 && i != 64)
+ break;
+#endif
+
+ type = mep_pragma_lex (&val);
+ if (type != CPP_PRAGMA_EOL)
+ warning (0, "junk at end of #pragma GCC coprocessor width");
+ return;
+
+ default:
+ break;
+ }
+
+ error ("#pragma GCC coprocessor width takes only 32 or 64");
+}
+
+static void
+mep_pragma_coprocessor_subclass (void)
+{
+ tree val;
+ enum cpp_ttype type;
+ HARD_REG_SET set;
+ int class_letter;
+ enum reg_class rclass;
+
+ type = mep_pragma_lex (&val);
+ if (type != CPP_CHAR)
+ goto syntax_error;
+ class_letter = tree_to_uhwi (val);
+ if (class_letter >= 'A' && class_letter <= 'D')
+ switch (class_letter)
+ {
+ case 'A':
+ rclass = USER0_REGS;
+ break;
+ case 'B':
+ rclass = USER1_REGS;
+ break;
+ case 'C':
+ rclass = USER2_REGS;
+ break;
+ case 'D':
+ rclass = USER3_REGS;
+ break;
+ }
+ else
+ {
+ error ("#pragma GCC coprocessor subclass letter must be in [ABCD]");
+ return;
+ }
+ if (reg_class_size[rclass] > 0)
+ {
+ error ("#pragma GCC coprocessor subclass '%c' already defined",
+ class_letter);
+ return;
+ }
+
+ type = mep_pragma_lex (&val);
+ if (type != CPP_EQ)
+ goto syntax_error;
+
+ if (! parse_cr_set (&set))
+ return;
+
+ /* Fix up register class hierarchy. */
+ COPY_HARD_REG_SET (reg_class_contents[rclass], set);
+ mep_init_regs ();
+ return;
+
+ syntax_error:
+ error ("malformed #pragma GCC coprocessor subclass");
+}
+
+static void
+mep_pragma_disinterrupt (cpp_reader *reader ATTRIBUTE_UNUSED)
+{
+ tree val;
+ enum cpp_ttype type;
+ int saw_one = 0;
+
+ for (;;)
+ {
+ type = mep_pragma_lex (&val);
+ if (type == CPP_COMMA)
+ continue;
+ if (type != CPP_NAME)
+ break;
+ mep_note_pragma_disinterrupt (IDENTIFIER_POINTER (val));
+ saw_one = 1;
+ }
+ if (!saw_one || type != CPP_PRAGMA_EOL)
+ {
+ error ("malformed #pragma disinterrupt");
+ return;
+ }
+}
+
+static void
+mep_pragma_coprocessor (cpp_reader *reader ATTRIBUTE_UNUSED)
+{
+ tree val;
+ enum cpp_ttype type;
+
+ type = mep_pragma_lex (&val);
+ if (type != CPP_NAME)
+ {
+ error ("malformed #pragma GCC coprocessor");
+ return;
+ }
+
+ if (!TARGET_COP)
+ error ("coprocessor not enabled");
+
+ if (strcmp (IDENTIFIER_POINTER (val), "available") == 0)
+ mep_pragma_coprocessor_which (CW_AVAILABLE);
+ else if (strcmp (IDENTIFIER_POINTER (val), "call_saved") == 0)
+ mep_pragma_coprocessor_which (CW_CALL_SAVED);
+ else if (strcmp (IDENTIFIER_POINTER (val), "width") == 0)
+ mep_pragma_coprocessor_width ();
+ else if (strcmp (IDENTIFIER_POINTER (val), "subclass") == 0)
+ mep_pragma_coprocessor_subclass ();
+ else
+ error ("unknown #pragma GCC coprocessor %E", val);
+}
+
+static void
+mep_pragma_call (cpp_reader *reader ATTRIBUTE_UNUSED)
+{
+ tree val;
+ enum cpp_ttype type;
+ int saw_one = 0;
+
+ for (;;)
+ {
+ type = mep_pragma_lex (&val);
+ if (type == CPP_COMMA)
+ continue;
+ if (type != CPP_NAME)
+ break;
+ mep_note_pragma_call (IDENTIFIER_POINTER (val));
+ saw_one = 1;
+ }
+ if (!saw_one || type != CPP_PRAGMA_EOL)
+ {
+ error ("malformed #pragma call");
+ return;
+ }
+}
+
+void
+mep_register_pragmas (void)
+{
+ c_register_pragma ("custom", "io_volatile", mep_pragma_io_volatile);
+ c_register_pragma ("GCC", "coprocessor", mep_pragma_coprocessor);
+ c_register_pragma (0, "disinterrupt", mep_pragma_disinterrupt);
+ c_register_pragma (0, "call", mep_pragma_call);
+}