385 lines
8.1 KiB
C
385 lines
8.1 KiB
C
|
/* Definitions of Toshiba Media Processor
|
||
|
Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007, 2009 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 <stdio.h>
|
||
|
#include "config.h"
|
||
|
#include "system.h"
|
||
|
#include "coretypes.h"
|
||
|
#include "tm.h"
|
||
|
#include "tree.h"
|
||
|
#include "rtl.h"
|
||
|
#include "toplev.h"
|
||
|
#include "c-pragma.h"
|
||
|
#include "cpplib.h"
|
||
|
#include "hard-reg-set.h"
|
||
|
#include "output.h"
|
||
|
#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 };
|
||
|
|
||
|
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. */
|
||
|
save_register_info ();
|
||
|
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 (! host_integerp (val, 1))
|
||
|
break;
|
||
|
i = tree_low_cst (val, 1);
|
||
|
/* 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 class;
|
||
|
|
||
|
type = mep_pragma_lex (&val);
|
||
|
if (type != CPP_CHAR)
|
||
|
goto syntax_error;
|
||
|
class_letter = tree_low_cst (val, 1);
|
||
|
if (class_letter >= 'A' && class_letter <= 'D')
|
||
|
class = class_letter - 'A' + USER0_REGS;
|
||
|
else
|
||
|
{
|
||
|
error ("#pragma GCC coprocessor subclass letter must be in [ABCD]");
|
||
|
return;
|
||
|
}
|
||
|
if (reg_class_size[class] > 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[class], set);
|
||
|
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);
|
||
|
}
|