/* Subroutines for insn-output.c for NEC V850 series
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GNU CC.
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-#include <ctype.h>
#include "config.h"
+#include "system.h"
+#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "expr.h"
-#include "tree.h"
-#include "obstack.h"
+#include "function.h"
+#include "toplev.h"
+#include "cpplib.h"
+#include "c-lex.h"
+#include "ggc.h"
+#include "integrate.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+
+#ifndef streq
+#define streq(a,b) (strcmp (a, b) == 0)
+#endif
+
+/* Function prototypes for stupid compilers: */
+static void const_double_split PARAMS ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
+static int const_costs_int PARAMS ((HOST_WIDE_INT, int));
+static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
+static int ep_memory_offset PARAMS ((enum machine_mode, int));
+static void v850_set_data_area PARAMS ((tree, v850_data_area));
+const struct attribute_spec v850_attribute_table[];
+static tree v850_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree v850_handle_data_area_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static void v850_insert_attributes PARAMS ((tree, tree *));
+static void v850_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));
+static void v850_encode_data_area PARAMS ((tree));
+static void v850_encode_section_info PARAMS ((tree, int));
+static const char *v850_strip_name_encoding PARAMS ((const char *));
/* True if the current function has anonymous arguments. */
int current_function_anonymous_args;
{ "zda", (char *)0, 0, 32768 },
};
+/* Names of the various data areas used on the v850. */
+tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
+
+/* Track the current data area set by the data area pragma (which
+ can be nested). Tested by check_default_data_area. */
+data_area_stack_element * data_area_stack = NULL;
+
/* True if we don't need to check any more if the current
- function is an interrupt handler */
+ function is an interrupt handler. */
static int v850_interrupt_cache_p = FALSE;
/* Whether current function is an interrupt handler. */
static int v850_interrupt_p = FALSE;
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
+
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION v850_select_section
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING v850_strip_name_encoding
+
+struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
override_options ()
{
int i;
- extern int atoi ();
+ extern int atoi PARAMS ((const char *));
/* Parse -m{s,t,z}da=nnn switches */
for (i = 0; i < (int)SMALL_MEMORY_max; i++)
{
if (small_memory[i].value)
{
- if (!isdigit (*small_memory[i].value))
- error ("%s=%s is not numeric.",
+ if (!ISDIGIT (*small_memory[i].value))
+ error ("%s=%s is not numeric",
small_memory[i].name,
small_memory[i].value);
else
{
small_memory[i].max = atoi (small_memory[i].value);
if (small_memory[i].max > small_memory[i].physical_max)
- error ("%s=%s is too large.",
+ error ("%s=%s is too large",
small_memory[i].name,
small_memory[i].value);
}
switch (cum->nbytes / UNITS_PER_WORD)
{
case 0:
- result = gen_rtx (REG, mode, 6);
+ result = gen_rtx_REG (mode, 6);
break;
case 1:
- result = gen_rtx (REG, mode, 7);
+ result = gen_rtx_REG (mode, 7);
break;
case 2:
- result = gen_rtx (REG, mode, 8);
+ result = gen_rtx_REG (mode, 8);
break;
case 3:
- result = gen_rtx (REG, mode, 9);
+ result = gen_rtx_REG (mode, 9);
break;
default:
result = 0;
*p_high = CONST_DOUBLE_HIGH (x);
*p_low = CONST_DOUBLE_LOW (x);
return;
+
+ default:
+ break;
}
}
switch (code)
{
+ case 'c':
+ /* We use 'c' operands with symbols for .vtinherit */
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ output_addr_const(file, x);
+ break;
+ }
+ /* fall through */
case 'b':
case 'B':
- switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
- {
- case NE:
- fprintf (file, "bne");
- break;
- case EQ:
- fprintf (file, "be");
- break;
- case GE:
- fprintf (file, "bge");
- break;
- case GT:
- fprintf (file, "bgt");
- break;
- case LE:
- fprintf (file, "ble");
- break;
- case LT:
- fprintf (file, "blt");
- break;
- case GEU:
- fprintf (file, "bnl");
- break;
- case GTU:
- fprintf (file, "bh");
- break;
- case LEU:
- fprintf (file, "bnh");
- break;
- case LTU:
- fprintf (file, "bl");
- break;
- default:
- abort ();
- }
- break;
- switch (GET_CODE (x))
+ case 'C':
+ switch ((code == 'B' || code == 'C')
+ ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
{
case NE:
- fprintf (file, "be");
+ if (code == 'c' || code == 'C')
+ fprintf (file, "nz");
+ else
+ fprintf (file, "ne");
break;
case EQ:
- fprintf (file, "bne");
+ if (code == 'c' || code == 'C')
+ fprintf (file, "z");
+ else
+ fprintf (file, "e");
break;
case GE:
- fprintf (file, "blt");
+ fprintf (file, "ge");
break;
case GT:
- fprintf (file, "bgt");
+ fprintf (file, "gt");
break;
case LE:
- fprintf (file, "ble");
+ fprintf (file, "le");
break;
case LT:
- fprintf (file, "blt");
+ fprintf (file, "lt");
break;
case GEU:
- fprintf (file, "bnl");
+ fprintf (file, "nl");
break;
case GTU:
- fprintf (file, "bh");
+ fprintf (file, "h");
break;
case LEU:
- fprintf (file, "bnh");
+ fprintf (file, "nh");
break;
case LTU:
- fprintf (file, "bl");
+ fprintf (file, "l");
break;
default:
abort ();
case 'O':
if (special_symbolref_operand (x, VOIDmode))
{
- char* name;
+ const char *name;
if (GET_CODE (x) == SYMBOL_REF)
name = XSTR (x, 0);
else if (TDA_NAME_P (name))
fprintf (file, "tdaoff");
else
- abort();
+ abort ();
}
else
- abort();
+ abort ();
break;
case 'P':
if (special_symbolref_operand (x, VOIDmode))
output_addr_const (file, x);
else
- abort();
+ abort ();
break;
case 'Q':
if (special_symbolref_operand (x, VOIDmode))
{
- char* name;
+ const char *name;
if (GET_CODE (x) == SYMBOL_REF)
name = XSTR (x, 0);
else if (TDA_NAME_P (name))
fprintf (file, "ep");
else
- abort();
+ abort ();
}
else
- abort();
+ abort ();
break;
case 'R': /* 2nd word of a double. */
switch (GET_CODE (x))
{
- case REG:
- fprintf (file, reg_names[REGNO (x) + 1]);
- break;
- case MEM:
- print_operand_address (file,
- XEXP (adj_offsettable_operand (x, 4), 0));
- break;
+ case REG:
+ fprintf (file, reg_names[REGNO (x) + 1]);
+ break;
+ case MEM:
+ x = XEXP (adjust_address (x, SImode, 4), 0);
+ print_operand_address (file, x);
+ if (GET_CODE (x) == CONST_INT)
+ fprintf (file, "[r0]");
+ break;
+
+ default:
+ break;
}
break;
case 'S':
{
- /* if it's a referance to a TDA variable, use sst/sld vs. st/ld */
+ /* if it's a reference to a TDA variable, use sst/sld vs. st/ld */
if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
fputs ("s", file);
case '.': /* register r0 */
fputs (reg_names[0], file);
break;
+ case 'z': /* reg or zero */
+ if (x == const0_rtx)
+ fputs (reg_names[0], file);
+ else if (GET_CODE (x) == REG)
+ fputs (reg_names[REGNO (x)], file);
+ else
+ abort ();
+ break;
default:
switch (GET_CODE (x))
{
case MEM:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
- output_address (gen_rtx (PLUS, SImode,
- gen_rtx (REG, SImode, 0),
- XEXP (x, 0)));
+ output_address (gen_rtx_PLUS (SImode, gen_rtx (REG, SImode, 0),
+ XEXP (x, 0)));
else
output_address (XEXP (x, 0));
break;
fputs (reg_names[REGNO (x)], file);
break;
case SUBREG:
- fputs (reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)], file);
+ fputs (reg_names[subreg_regno (x)], file);
break;
case CONST_INT:
case SYMBOL_REF:
case SYMBOL_REF:
if (ENCODED_NAME_P (XSTR (addr, 0)))
{
- char* name = XSTR (addr, 0);
- char* off_name;
- char* reg_name;
+ const char *name = XSTR (addr, 0);
+ const char *off_name;
+ const char *reg_name;
if (ZDA_NAME_P (name))
{
reg_name = "ep";
}
else
- abort();
+ abort ();
fprintf (file, "%s(", off_name);
output_addr_const (file, addr);
case CONST:
if (special_symbolref_operand (addr, VOIDmode))
{
- char* name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
- char* off_name;
- char* reg_name;
+ const char *name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
+ const char *off_name;
+ const char *reg_name;
if (ZDA_NAME_P (name))
{
reg_name = "ep";
}
else
- abort();
+ abort ();
fprintf (file, "%s(", off_name);
output_addr_const (file, addr);
/* Return appropriate code to load up a 1, 2, or 4 integer/floating
point value. */
-char *
+const char *
output_move_single (operands)
rtx *operands;
{
return "%S0st%W0 %.,%0";
}
- fatal_insn ("output_move_single:", gen_rtx (SET, VOIDmode, dst, src));
+ fatal_insn ("output_move_single:", gen_rtx_SET (VOIDmode, dst, src));
return "";
}
\f
-/* Return appropriate code to load up an 8 byte integer or floating point value */
+/* Return appropriate code to load up an 8 byte integer or
+ floating point value */
-char *
+const char *
output_move_double (operands)
rtx *operands;
{
for (i = 0; i < 2; i++)
{
- xop[0] = gen_rtx (REG, SImode, REGNO (dst)+i);
+ xop[0] = gen_rtx_REG (SImode, REGNO (dst)+i);
xop[1] = GEN_INT (high_low[i]);
output_asm_insn (output_move_single (xop), xop);
}
if (GET_CODE (inside) == REG)
ptrreg = REGNO (inside);
else if (GET_CODE (inside) == SUBREG)
- ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside);
+ ptrreg = subreg_regno (inside);
else if (GET_CODE (inside) == PLUS)
ptrreg = REGNO (XEXP (inside, 0));
else if (GET_CODE (inside) == LO_SUM)
}
\f
-/* Return true if OP is a valid short EP memory reference */
+/* Return maximum offset supported for a short EP memory reference of mode
+ MODE and signedness UNSIGNEDP. */
-int
-ep_memory_operand (op, mode, unsigned_load)
- rtx op;
+static int
+ep_memory_offset (mode, unsignedp)
enum machine_mode mode;
- int unsigned_load;
+ int ATTRIBUTE_UNUSED unsignedp;
{
- rtx addr, op0, op1;
- int max_offset;
- int mask;
-
- if (GET_CODE (op) != MEM)
- return FALSE;
+ int max_offset = 0;
- switch (GET_MODE (op))
+ switch (mode)
{
- default:
- return FALSE;
-
case QImode:
- max_offset = (1 << 7);
- mask = 0;
+ max_offset = (1 << 7);
break;
case HImode:
- max_offset = (1 << 8);
- mask = 1;
+ max_offset = (1 << 8);
break;
case SImode:
case SFmode:
max_offset = (1 << 8);
- mask = 3;
+ break;
+
+ default:
break;
}
+ return max_offset;
+}
+
+/* Return true if OP is a valid short EP memory reference */
+
+int
+ep_memory_operand (op, mode, unsigned_load)
+ rtx op;
+ enum machine_mode mode;
+ int unsigned_load;
+{
+ rtx addr, op0, op1;
+ int max_offset;
+ int mask;
+
+ if (GET_CODE (op) != MEM)
+ return FALSE;
+
+ max_offset = ep_memory_offset (mode, unsigned_load);
+
+ mask = GET_MODE_SIZE (mode) - 1;
+
addr = XEXP (op, 0);
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
op1 = XEXP (addr, 1);
if (GET_CODE (op1) == CONST_INT
&& INTVAL (op1) < max_offset
+ && INTVAL (op1) >= 0
&& (INTVAL (op1) & mask) == 0)
{
if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM)
else if (GET_CODE (op) == CONST_DOUBLE)
return CONST_DOUBLE_OK_FOR_G (op);
- else if (GET_CODE (op) == REG)
- return TRUE;
-
- else if (GET_CODE (op) == SUBREG)
- {
- do {
- op = SUBREG_REG (op);
- } while (GET_CODE (op) == SUBREG);
-
- if (GET_CODE (op) == MEM && !reload_completed)
- return TRUE;
-
- else if (GET_CODE (op) == REG)
- return TRUE;
- }
-
- return FALSE;
+ else
+ return register_operand (op, mode);
}
/* Return true if OP is either a register or a signed five bit integer */
if (GET_CODE (op) == CONST_INT)
return CONST_OK_FOR_J (INTVAL (op));
- else if (GET_CODE (op) == REG)
- return TRUE;
-
- else if (GET_CODE (op) == SUBREG)
- {
- do {
- op = SUBREG_REG (op);
- } while (GET_CODE (op) == SUBREG);
-
- if (GET_CODE (op) == MEM && !reload_completed)
- return TRUE;
-
- else if (GET_CODE (op) == REG)
- return TRUE;
- }
-
- return FALSE;
+ else
+ return register_operand (op, mode);
}
/* Return true if OP is a valid call operand. */
int
call_address_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
/* Only registers are valid call operands if TARGET_LONG_CALLS. */
if (TARGET_LONG_CALLS)
int
special_symbolref_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
if (GET_CODE (op) == SYMBOL_REF)
return ENCODED_NAME_P (XSTR (op, 0));
must be done with HIGH & LO_SUM patterns. */
if (CONSTANT_P (op)
&& GET_CODE (op) != HIGH
+ && GET_CODE (op) != CONSTANT_P_RTX
&& !(GET_CODE (op) == CONST_INT
&& (CONST_OK_FOR_J (INTVAL (op))
|| CONST_OK_FOR_K (INTVAL (op))
int
power_of_two_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
if (GET_CODE (op) != CONST_INT)
return 0;
else if (mode == HImode)
mask = 0xffff;
else if (mode == SImode)
- mask = 0xffffffff;
+ mask = 0xffffffff;
else
return 0;
rtx *p_r1;
rtx *p_ep;
{
- rtx reg = gen_rtx (REG, Pmode, regno);
+ rtx reg = gen_rtx_REG (Pmode, regno);
rtx insn;
- int i;
if (!*p_r1)
{
regs_ever_live[1] = 1;
- *p_r1 = gen_rtx (REG, Pmode, 1);
- *p_ep = gen_rtx (REG, Pmode, 30);
+ *p_r1 = gen_rtx_REG (Pmode, 1);
+ *p_ep = gen_rtx_REG (Pmode, 30);
}
if (TARGET_DEBUG)
- fprintf (stderr, "Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
+ fprintf (stderr, "\
+Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
2 * (uses - 3), uses, reg_names[regno],
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
INSN_UID (first_insn), INSN_UID (last_insn));
if (pattern)
{
rtx *p_mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
if (GET_CODE (SET_DEST (pattern)) == MEM
&& GET_CODE (SET_SRC (pattern)) == MEM)
{
rtx addr = XEXP (*p_mem, 0);
- if (GET_CODE (addr) == REG && REGNO (addr) == regno)
+ if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno)
*p_mem = change_address (*p_mem, VOIDmode, *p_ep);
else if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == REG
- && REGNO (XEXP (addr, 0)) == regno
+ && REGNO (XEXP (addr, 0)) == (unsigned) regno
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
- && (GET_MODE (*p_mem) != QImode
- || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+ && ((INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (*p_mem),
+ unsignedp))
+ && ((INTVAL (XEXP (addr, 1))) >= 0))
*p_mem = change_address (*p_mem, VOIDmode,
- gen_rtx (PLUS, Pmode,
- *p_ep, XEXP (addr, 1)));
+ gen_rtx_PLUS (Pmode,
+ *p_ep,
+ XEXP (addr, 1)));
}
}
}
&& SET_SRC (PATTERN (insn)) == *p_r1)
delete_insn (insn);
else
- emit_insn_before (gen_rtx (SET, Pmode, *p_r1, *p_ep), first_insn);
+ emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn);
- emit_insn_before (gen_rtx (SET, Pmode, *p_ep, reg), first_insn);
- emit_insn_before (gen_rtx (SET, Pmode, *p_ep, *p_r1), last_insn);
+ emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn);
+ emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);
}
\f
as a C statement to act on the code starting at INSN.
On the 850, we use it to implement the -mep mode to copy heavily used
- pointers to ep to use the implicit addressing */
+ pointers to ep to use the implicit addressing. */
void v850_reorg (start_insn)
rtx start_insn;
{
- struct {
+ struct
+ {
int uses;
rtx first_insn;
rtx last_insn;
- } regs[FIRST_PSEUDO_REGISTER];
+ }
+ regs[FIRST_PSEUDO_REGISTER];
int i;
int use_ep = FALSE;
rtx insn;
rtx pattern;
- /* If not ep mode, just return now */
+ /* If not ep mode, just return now. */
if (!TARGET_EP)
return;
rtx src = SET_SRC (pattern);
rtx dest = SET_DEST (pattern);
rtx mem;
+ /* Memory operands are signed by default. */
+ int unsignedp = FALSE;
+
+ /* We might have (SUBREG (MEM)) here, so just get rid of the
+ subregs to make this code simpler. */
+ if (GET_CODE (dest) == SUBREG
+ && (GET_CODE (SUBREG_REG (dest)) == MEM
+ || GET_CODE (SUBREG_REG (dest)) == REG))
+ alter_subreg (&dest);
+ if (GET_CODE (src) == SUBREG
+ && (GET_CODE (SUBREG_REG (src)) == MEM
+ || GET_CODE (SUBREG_REG (src)) == REG))
+ alter_subreg (&src);
if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
mem = NULL_RTX;
else
mem = NULL_RTX;
- if (mem && ep_memory_operand (mem, GET_MODE (mem), FALSE))
+ if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
use_ep = TRUE;
else if (!use_ep && mem
else if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == REG
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((unsigned)INTVAL (XEXP (addr, 1))) < 256
- && (GET_MODE (mem) != QImode
- || ((unsigned)INTVAL (XEXP (addr, 1))) < 128))
+ && ((INTVAL (XEXP (addr, 1)))
+ < ep_memory_offset (GET_MODE (mem), unsignedp))
+ && ((INTVAL (XEXP (addr, 1))) >= 0))
{
short_p = TRUE;
regno = REGNO (XEXP (addr, 0));
/* Loading up a register in the basic block zaps any savings
for the register */
- if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
+ if (GET_CODE (dest) == REG)
{
enum machine_mode mode = GET_MODE (dest);
- int word = 0;
int regno;
int endregno;
- while (GET_CODE (dest) == SUBREG)
- {
- word = SUBREG_WORD (dest);
- dest = SUBREG_REG (dest);
- }
-
- regno = REGNO (dest) + word;
+ regno = REGNO (dest);
endregno = regno + HARD_REGNO_NREGS (regno, mode);
if (!use_ep)
{
substitute_ep_register (regs[max_regno].first_insn,
regs[max_regno].last_insn,
- max_uses, max_regno, &r1, &ep);
+ max_uses, max_regno, &r1,
+ &ep);
/* Since we made a substitution, zap all remembered
registers. */
int size = 0;
int i;
int interrupt_handler = v850_interrupt_function_p (current_function_decl);
- int call_p = regs_ever_live[31];
+ int call_p = regs_ever_live [LINK_POINTER_REGNUM];
long reg_saved = 0;
/* Count the return pointer if we need to save it. */
- if (profile_flag && !call_p)
- regs_ever_live[31] = call_p = 1;
+ if (current_function_profile && !call_p)
+ regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
/* Count space for the register saves. */
if (interrupt_handler)
These registers are handled specially, so don't list them
on the list of registers to save in the prologue. */
case 1: /* temp used to hold ep */
- case 5: /* gp */
+ case 4: /* gp */
case 10: /* temp used to call interrupt save/restore */
case EP_REGNUM: /* ep */
size += 4;
break;
}
}
-
else
- for (i = 0; i <= 31; i++)
- if (regs_ever_live[i] && ((! call_used_regs[i]) || i == 31))
+ {
+ /* Find the first register that needs to be saved. */
+ for (i = 0; i <= 31; i++)
+ if (regs_ever_live[i] && ((! call_used_regs[i])
+ || i == LINK_POINTER_REGNUM))
+ break;
+
+ /* If it is possible that an out-of-line helper function might be
+ used to generate the prologue for the current function, then we
+ need to cover the possibility that such a helper function will
+ be used, despite the fact that there might be gaps in the list of
+ registers that need to be saved. To detect this we note that the
+ helper functions always push at least register r29 (provided
+ that the function is not an interrupt handler). */
+
+ if (TARGET_PROLOG_FUNCTION
+ && (i == 2 || ((i >= 20) && (i < 30))))
{
- size += 4;
- reg_saved |= 1L << i;
- }
+ if (i == 2)
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+
+ i = 20;
+ }
+
+ /* Helper functions save all registers between the starting
+ register and the last register, regardless of whether they
+ are actually used by the function or not. */
+ for (; i <= 29; i++)
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+ }
+ if (regs_ever_live [LINK_POINTER_REGNUM])
+ {
+ size += 4;
+ reg_saved |= 1L << LINK_POINTER_REGNUM;
+ }
+ }
+ else
+ {
+ for (; i <= 31; i++)
+ if (regs_ever_live[i] && ((! call_used_regs[i])
+ || i == LINK_POINTER_REGNUM))
+ {
+ size += 4;
+ reg_saved |= 1L << i;
+ }
+ }
+ }
+
if (p_reg_saved)
*p_reg_saved = reg_saved;
int size;
long *p_reg_saved;
{
- extern int current_function_outgoing_args_size;
-
return (size
+ compute_register_save_size (p_reg_saved)
+ current_function_outgoing_args_size);
unsigned int init_stack_alloc = 0;
rtx save_regs[32];
rtx save_all;
- int num_save;
- int default_stack;
+ unsigned int num_save;
+ unsigned int default_stack;
int code;
int interrupt_handler = v850_interrupt_function_p (current_function_decl);
long reg_saved = 0;
actual_fsize = compute_frame_size (size, ®_saved);
- /* Save/setup global registers for interrupt functions right now */
+ /* Save/setup global registers for interrupt functions right now. */
if (interrupt_handler)
{
- emit_insn (gen_save_interrupt ());
+ emit_insn (gen_save_interrupt ());
+
actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
- if (((1L << 31) & reg_saved) != 0)
+
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
}
else if (current_function_anonymous_args)
{
if (TARGET_PROLOG_FUNCTION)
- emit_insn (gen_save_r6_r9 ());
+ {
+ emit_insn (gen_save_r6_r9 ());
+ }
else
{
offset = 0;
for (i = 6; i < 10; i++)
{
- emit_move_insn (gen_rtx (MEM, SImode,
- plus_constant (stack_pointer_rtx,
- offset)),
- gen_rtx (REG, SImode, i));
+ emit_move_insn (gen_rtx_MEM (SImode,
+ plus_constant (stack_pointer_rtx,
+ offset)),
+ gen_rtx_REG (SImode, i));
offset += 4;
}
}
}
- /* Identify all of the saved registers */
+ /* Identify all of the saved registers. */
num_save = 0;
default_stack = 0;
for (i = 1; i < 31; i++)
{
if (((1L << i) & reg_saved) != 0)
- save_regs[num_save++] = gen_rtx (REG, Pmode, i);
+ save_regs[num_save++] = gen_rtx_REG (Pmode, i);
}
/* If the return pointer is saved, the helper functions also allocate
16 bytes of stack for arguments to be saved in. */
- if (((1L << 31) & reg_saved) != 0)
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
- save_regs[num_save++] = gen_rtx (REG, Pmode, 31);
+ save_regs[num_save++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
default_stack = 16;
}
stack space is allocated. */
if (save_func_len < save_normal_len)
{
- save_all = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num_save + (TARGET_V850 ? 2 : 1)));
- XVECEXP (save_all, 0, 0) = gen_rtx (SET, VOIDmode,
- stack_pointer_rtx,
- gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (-alloc_stack)));
+ save_all = gen_rtx_PARALLEL
+ (VOIDmode,
+ rtvec_alloc (num_save + (TARGET_V850 ? 2 : 1)));
+
+ XVECEXP (save_all, 0, 0)
+ = gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx, -alloc_stack));
if (TARGET_V850)
{
XVECEXP (save_all, 0, num_save+1)
- = gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, Pmode, 10));
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));
}
offset = - default_stack;
for (i = 0; i < num_save; i++)
{
XVECEXP (save_all, 0, i+1)
- = gen_rtx (SET, VOIDmode,
- gen_rtx (MEM, Pmode,
- plus_constant (stack_pointer_rtx, offset)),
- save_regs[i]);
+ = gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (Pmode,
+ plus_constant (stack_pointer_rtx,
+ offset)),
+ save_regs[i]);
offset -= 4;
}
- code = recog (save_all, NULL_RTX, NULL_PTR);
+ code = recog (save_all, NULL_RTX, NULL);
if (code >= 0)
{
rtx insn = emit_insn (save_all);
INSN_CODE (insn) = code;
actual_fsize -= alloc_stack;
-
+
if (TARGET_DEBUG)
- fprintf (stderr, "Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
+ fprintf (stderr, "\
+Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
save_normal_len - save_func_len,
save_normal_len, save_func_len,
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
}
}
- /* If no prolog save function is available, store the registers the old fashioned
- way (one by one). */
+ /* If no prolog save function is available, store the registers the old
+ fashioned way (one by one). */
if (!save_all)
{
/* Special case interrupt functions that save all registers for a call. */
- if (interrupt_handler && ((1L << 31) & reg_saved) != 0)
- emit_insn (gen_save_all_interrupt ());
-
+ if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ {
+ emit_insn (gen_save_all_interrupt ());
+ }
else
{
/* If the stack is too big, allocate it in chunks so we can do the
GEN_INT (-init_stack_alloc)));
/* Save the return pointer first. */
- if (num_save > 0 && REGNO (save_regs[num_save-1]) == 31)
+ if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
{
- emit_move_insn (gen_rtx (MEM, SImode,
- plus_constant (stack_pointer_rtx,
- offset)),
+ emit_move_insn (gen_rtx_MEM (SImode,
+ plus_constant (stack_pointer_rtx,
+ offset)),
save_regs[--num_save]);
offset -= 4;
}
for (i = 0; i < num_save; i++)
{
- emit_move_insn (gen_rtx (MEM, SImode,
- plus_constant (stack_pointer_rtx,
- offset)),
+ emit_move_insn (gen_rtx_MEM (SImode,
+ plus_constant (stack_pointer_rtx,
+ offset)),
save_regs[i]);
offset -= 4;
}
GEN_INT (-diff)));
else
{
- rtx reg = gen_rtx (REG, Pmode, 12);
+ rtx reg = gen_rtx_REG (Pmode, 12);
emit_move_insn (reg, GEN_INT (-diff));
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
}
unsigned int init_stack_free = 0;
rtx restore_regs[32];
rtx restore_all;
- int num_restore;
- int default_stack;
+ unsigned int num_restore;
+ unsigned int default_stack;
int code;
int interrupt_handler = v850_interrupt_function_p (current_function_decl);
if (interrupt_handler)
{
actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
- if (((1L << 31) & reg_saved) != 0)
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
}
if (frame_pointer_needed)
emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
- /* Identify all of the saved registers */
+ /* Identify all of the saved registers. */
num_restore = 0;
default_stack = 0;
for (i = 1; i < 31; i++)
{
if (((1L << i) & reg_saved) != 0)
- restore_regs[num_restore++] = gen_rtx (REG, Pmode, i);
+ restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);
}
/* If the return pointer is saved, the helper functions also allocate
16 bytes of stack for arguments to be saved in. */
- if (((1L << 31) & reg_saved) != 0)
+ if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
- restore_regs[num_restore++] = gen_rtx (REG, Pmode, 31);
+ restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
default_stack = 16;
}
/* See if we have an insn that restores the particular registers we
want to. */
restore_all = NULL_RTX;
- if (TARGET_PROLOG_FUNCTION && num_restore > 0 && actual_fsize >= default_stack
+
+ if (TARGET_PROLOG_FUNCTION
+ && num_restore > 0
+ && actual_fsize >= default_stack
&& !interrupt_handler)
{
int alloc_stack = (4 * num_restore) + default_stack;
if (unalloc_stack)
restore_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
- /* see if we would have used ep to restore the registers */
+ /* See if we would have used ep to restore the registers. */
if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)
restore_normal_len = (3 * 2) + (2 * num_restore);
else
/* Don't bother checking if we don't actually save any space. */
if (restore_func_len < restore_normal_len)
{
- restore_all = gen_rtx (PARALLEL, VOIDmode,
- rtvec_alloc (num_restore + 2));
- XVECEXP (restore_all, 0, 0) = gen_rtx (RETURN, VOIDmode);
+ restore_all = gen_rtx_PARALLEL (VOIDmode,
+ rtvec_alloc (num_restore + 2));
+ XVECEXP (restore_all, 0, 0) = gen_rtx_RETURN (VOIDmode);
XVECEXP (restore_all, 0, 1)
- = gen_rtx (SET, VOIDmode, stack_pointer_rtx,
- gen_rtx (PLUS, Pmode,
- stack_pointer_rtx,
- GEN_INT (alloc_stack)));
+ = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (alloc_stack)));
offset = alloc_stack - 4;
for (i = 0; i < num_restore; i++)
{
XVECEXP (restore_all, 0, i+2)
- = gen_rtx (SET, VOIDmode,
- restore_regs[i],
- gen_rtx (MEM, Pmode,
- plus_constant (stack_pointer_rtx, offset)));
+ = gen_rtx_SET (VOIDmode,
+ restore_regs[i],
+ gen_rtx_MEM (Pmode,
+ plus_constant (stack_pointer_rtx,
+ offset)));
offset -= 4;
}
- code = recog (restore_all, NULL_RTX, NULL_PTR);
+ code = recog (restore_all, NULL_RTX, NULL);
+
if (code >= 0)
{
rtx insn;
GEN_INT (actual_fsize)));
else
{
- rtx reg = gen_rtx (REG, Pmode, 12);
+ rtx reg = gen_rtx_REG (Pmode, 12);
emit_move_insn (reg, GEN_INT (actual_fsize));
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
INSN_CODE (insn) = code;
if (TARGET_DEBUG)
- fprintf (stderr, "Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
+ fprintf (stderr, "\
+Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
restore_normal_len - restore_func_len,
restore_normal_len, restore_func_len,
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
}
/* If no epilog save function is available, restore the registers the
- old fashioned way (one by one). */
+ old fashioned way (one by one). */
if (!restore_all)
{
/* If the stack is large, we need to cut it down in 2 pieces. */
else
init_stack_free = actual_fsize;
- /* Deallocate the rest of the stack if it is > 32K or if extra stack
- was allocated for an interrupt handler that makes a call. */
- if (actual_fsize > init_stack_free || (interrupt_handler && actual_fsize))
+ /* Deallocate the rest of the stack if it is > 32K. */
+ if (actual_fsize > init_stack_free)
{
- int diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
+ int diff;
+
+ diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
+
if (CONST_OK_FOR_K (diff))
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (diff)));
else
{
- rtx reg = gen_rtx (REG, Pmode, 12);
+ rtx reg = gen_rtx_REG (Pmode, 12);
emit_move_insn (reg, GEN_INT (diff));
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
/* Special case interrupt functions that save all registers
for a call. */
- if (interrupt_handler && ((1L << 31) & reg_saved) != 0)
- emit_insn (gen_restore_all_interrupt ());
+ if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
+ {
+ emit_insn (gen_restore_all_interrupt ());
+ }
else
{
- /* Restore registers from the beginning of the stack frame */
+ /* Restore registers from the beginning of the stack frame. */
offset = init_stack_free - 4;
/* Restore the return pointer first. */
- if (num_restore > 0 && REGNO (restore_regs[num_restore-1]) == 31)
+ if (num_restore > 0
+ && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)
{
emit_move_insn (restore_regs[--num_restore],
- gen_rtx (MEM, SImode,
- plus_constant (stack_pointer_rtx,
- offset)));
+ gen_rtx_MEM (SImode,
+ plus_constant (stack_pointer_rtx,
+ offset)));
offset -= 4;
}
for (i = 0; i < num_restore; i++)
{
emit_move_insn (restore_regs[i],
- gen_rtx (MEM, SImode,
- plus_constant (stack_pointer_rtx,
- offset)));
+ gen_rtx_MEM (SImode,
+ plus_constant (stack_pointer_rtx,
+ offset)));
+ emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
offset -= 4;
}
case CC_NONE_0HIT:
/* Insn does not change CC, but the 0'th operand has been changed. */
if (cc_status.value1 != 0
- && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
+ && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
cc_status.value1 = 0;
break;
case CC_SET_ZN:
- /* Insn sets the Z,N flags of CC to recog_operand[0].
+ /* Insn sets the Z,N flags of CC to recog_data.operand[0].
V,C is in an unusable state. */
CC_STATUS_INIT;
cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
- cc_status.value1 = recog_operand[0];
+ cc_status.value1 = recog_data.operand[0];
break;
case CC_SET_ZNV:
- /* Insn sets the Z,N,V flags of CC to recog_operand[0].
+ /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].
C is in an unusable state. */
CC_STATUS_INIT;
cc_status.flags |= CC_NO_CARRY;
- cc_status.value1 = recog_operand[0];
+ cc_status.value1 = recog_data.operand[0];
break;
case CC_COMPARE:
break;
}
}
-
\f
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ATTRIBUTES are any existing attributes and ARGS are the arguments
- supplied with ATTR.
+/* Retrieve the data area that has been chosen for the given decl. */
+
+v850_data_area
+v850_get_data_area (decl)
+ tree decl;
+{
+ if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_SDA;
+
+ if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_TDA;
+
+ if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
+ return DATA_AREA_ZDA;
- Supported attributes:
+ return DATA_AREA_NORMAL;
+}
- interrupt_handler or interrupt: output a prologue and epilogue suitable
- for an interrupt handler. */
+/* Store the indicated data area in the decl's attributes. */
-int
-v850_valid_machine_decl_attribute (decl, attributes, attr, args)
+static void
+v850_set_data_area (decl, data_area)
tree decl;
- tree attributes;
- tree attr;
- tree args;
+ v850_data_area data_area;
{
- if (args != NULL_TREE)
- return 0;
+ tree name;
+
+ switch (data_area)
+ {
+ case DATA_AREA_SDA: name = get_identifier ("sda"); break;
+ case DATA_AREA_TDA: name = get_identifier ("tda"); break;
+ case DATA_AREA_ZDA: name = get_identifier ("zda"); break;
+ default:
+ return;
+ }
+
+ DECL_ATTRIBUTES (decl) = tree_cons
+ (name, NULL, DECL_ATTRIBUTES (decl));
+}
+\f
+const struct attribute_spec v850_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt_handler", 0, 0, true, false, false, v850_handle_interrupt_attribute },
+ { "interrupt", 0, 0, true, false, false, v850_handle_interrupt_attribute },
+ { "sda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { "tda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { "zda", 0, 0, true, false, false, v850_handle_data_area_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+/* Handle an "interrupt" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "sda", "tda" or "zda" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_data_area_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ v850_data_area data_area;
+ v850_data_area area;
+ tree decl = *node;
+
+ /* Implement data area attribute. */
+ if (is_attribute_p ("sda", name))
+ data_area = DATA_AREA_SDA;
+ else if (is_attribute_p ("tda", name))
+ data_area = DATA_AREA_TDA;
+ else if (is_attribute_p ("zda", name))
+ data_area = DATA_AREA_ZDA;
+ else
+ abort ();
+
+ switch (TREE_CODE (decl))
+ {
+ case VAR_DECL:
+ if (current_function_decl != NULL_TREE)
+ {
+ error_with_decl (decl, "\
+a data area attribute cannot be specified for local variables");
+ *no_add_attrs = true;
+ }
+
+ /* Drop through. */
- if (is_attribute_p ("interrupt_handler", attr)
- || is_attribute_p ("interrupt", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ case FUNCTION_DECL:
+ area = v850_get_data_area (decl);
+ if (area != DATA_AREA_NORMAL && data_area != area)
+ {
+ error_with_decl (decl, "\
+data area of '%s' conflicts with previous declaration");
+ *no_add_attrs = true;
+ }
+ break;
+
+ default:
+ break;
+ }
- return 0;
+ return NULL_TREE;
}
\f
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
if (a != NULL_TREE)
ret = 1;
else
{
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
ret = a != NULL_TREE;
}
}
\f
-extern struct obstack *saveable_obstack;
-
+static void
v850_encode_data_area (decl)
tree decl;
{
- char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
- int len = strlen (str);
- char *newstr;
+ const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ int len = strlen (str);
+ char * newstr;
+
+ /* Map explict sections into the appropriate attribute */
+ if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ {
+ if (DECL_SECTION_NAME (decl))
+ {
+ const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+
+ if (streq (name, ".zdata") || streq (name, ".zbss"))
+ v850_set_data_area (decl, DATA_AREA_ZDA);
+
+ else if (streq (name, ".sdata") || streq (name, ".sbss"))
+ v850_set_data_area (decl, DATA_AREA_SDA);
+
+ else if (streq (name, ".tdata"))
+ v850_set_data_area (decl, DATA_AREA_TDA);
+ }
+
+ /* If no attribute, support -m{zda,sda,tda}=n */
+ else
+ {
+ int size = int_size_in_bytes (TREE_TYPE (decl));
+ if (size <= 0)
+ ;
+
+ else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max)
+ v850_set_data_area (decl, DATA_AREA_TDA);
+
+ else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max)
+ v850_set_data_area (decl, DATA_AREA_SDA);
+
+ else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max)
+ v850_set_data_area (decl, DATA_AREA_ZDA);
+ }
+
+ if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ return;
+ }
+
+ newstr = alloca (len + 2);
+
+ strcpy (newstr + 1, str);
+
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA: *newstr = ZDA_NAME_FLAG_CHAR; break;
+ case DATA_AREA_TDA: *newstr = TDA_NAME_FLAG_CHAR; break;
+ case DATA_AREA_SDA: *newstr = SDA_NAME_FLAG_CHAR; break;
+ default: abort ();
+ }
+
+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 2);
+}
+
+static void
+v850_encode_section_info (decl, first)
+ tree decl;
+ int first;
+{
+ if (first && TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ v850_encode_data_area (decl);
+}
- /* In the Cygnus sources we actually do something; this is just
- here to make merges easier. */
- return;
+static const char *
+v850_strip_name_encoding (str)
+ const char *str;
+{
+ return str + (ENCODED_NAME_P (str) || *str == '*');
}
/* Return true if the given RTX is a register which can be restored
int
register_is_ok_for_epilogue (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
/* The save/restore routines can only cope with registers 2, and 20 - 31 */
return (GET_CODE (op) == REG)
int
pattern_is_ok_for_epilogue (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
int count = XVECLEN (op, 0);
int i;
if (count <= 2)
{
- error ("Bogus JR construction: %d\n", count);
+ error ("bogus JR construction: %d\n", count);
return NULL;
}
/* Make sure that the amount we are popping either 0 or 16 bytes. */
if (stack_bytes != 0 && stack_bytes != 16)
{
- error ("Bad amount of stack space removal: %d", stack_bytes);
+ error ("bad amount of stack space removal: %d", stack_bytes);
return NULL;
}
abort ();
/* Discover the last register to pop. */
- if (mask & (1 << 31))
+ if (mask & (1 << LINK_POINTER_REGNUM))
{
if (stack_bytes != 16)
abort ();
- last = 31;
+ last = LINK_POINTER_REGNUM;
}
else
{
if (stack_bytes != 0)
abort ();
+
if ((mask & (1 << 29)) == 0)
abort ();
last = 29;
}
- /* Paranoia */
- for (i = (first == 2 ? 20 : first + 1); i < 29; i++)
- if ((mask & (1 << i)) == 0)
- abort ();
-
- if (first == last)
- sprintf (buff, "jr __return_%s", reg_names [first]);
+ /* Note, it is possible to have gaps in the register mask.
+ We ignore this here, and generate a JR anyway. We will
+ be popping more registers than is strictly necessary, but
+ it does save code space. */
+
+ if (TARGET_LONG_CALLS)
+ {
+ char name[40];
+
+ if (first == last)
+ sprintf (name, "__return_%s", reg_names [first]);
+ else
+ sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);
+
+ sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",
+ name, name);
+ }
else
- sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
-
+ {
+ if (first == last)
+ sprintf (buff, "jr __return_%s", reg_names [first]);
+ else
+ sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
+ }
+
return buff;
}
int
pattern_is_ok_for_prologue (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode ATTRIBUTE_UNUSED mode;
{
int count = XVECLEN (op, 0);
int i;
return 0;
/* If the register is being pushed somewhere other than the stack
- space just aquired by the first operand then abandon this quest.
- Note: the test is <= becuase both values are negative. */
+ space just acquired by the first operand then abandon this quest.
+ Note: the test is <= because both values are negative. */
if (INTVAL (XEXP (plus, 1))
<= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
{
if (count <= 2)
{
- error ("Bogus JARL construction: %d\n", count);
+ error ("bogus JARL construction: %d\n", count);
return NULL;
}
/* Make sure that the amount we are popping either 0 or 16 bytes. */
if (stack_bytes != 0 && stack_bytes != -16)
{
- error ("Bad amount of stack space removal: %d", stack_bytes);
+ error ("bad amount of stack space removal: %d", stack_bytes);
return NULL;
}
abort ();
/* Discover the last register to push. */
- if (mask & (1 << 31))
+ if (mask & (1 << LINK_POINTER_REGNUM))
{
if (stack_bytes != -16)
- abort();
+ abort ();
- last = 31;
+ last = LINK_POINTER_REGNUM;
}
else
{
last = 29;
}
- /* Paranoia */
- for (i = (first == 2 ? 20 : first + 1); i < 29; i++)
- if ((mask & (1 << i)) == 0)
- abort ();
-
- if (first == last)
- sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
+ /* Note, it is possible to have gaps in the register mask.
+ We ignore this here, and generate a JARL anyway. We will
+ be pushing more registers than is strictly necessary, but
+ it does save code space. */
+
+ if (TARGET_LONG_CALLS)
+ {
+ char name[40];
+
+ if (first == last)
+ sprintf (name, "__save_%s", reg_names [first]);
+ else
+ sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]);
+
+ sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11",
+ name, name);
+ }
else
- sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
- reg_names [last]);
+ {
+ if (first == last)
+ sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
+ else
+ sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
+ reg_names [last]);
+ }
return buff;
}
+extern tree last_assemble_variable_decl;
+extern int size_directive_output;
+
+/* A version of asm_output_aligned_bss() that copes with the special
+ data areas of the v850. */
+void
+v850_output_aligned_bss (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ ASM_GLOBALIZE_LABEL (file, name);
+
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ zbss_section ();
+ break;
+
+ case DATA_AREA_SDA:
+ sbss_section ();
+ break;
+
+ case DATA_AREA_TDA:
+ tdata_section ();
+
+ default:
+ bss_section ();
+ break;
+ }
+
+ ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+ ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_COMMON */
+void
+v850_output_common (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ if (decl == NULL_TREE)
+ {
+ fprintf (file, "%s", COMMON_ASM_OP);
+ }
+ else
+ {
+ switch (v850_get_data_area (decl))
+ {
+ case DATA_AREA_ZDA:
+ fprintf (file, "%s", ZCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_SDA:
+ fprintf (file, "%s", SCOMMON_ASM_OP);
+ break;
+
+ case DATA_AREA_TDA:
+ fprintf (file, "%s", TCOMMON_ASM_OP);
+ break;
+
+ default:
+ fprintf (file, "%s", COMMON_ASM_OP);
+ break;
+ }
+ }
+
+ assemble_name (file, name);
+ fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
+}
+
+/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
+void
+v850_output_local (file, decl, name, size, align)
+ FILE * file;
+ tree decl;
+ const char * name;
+ int size;
+ int align;
+{
+ fprintf (file, "%s", LOCAL_ASM_OP);
+ assemble_name (file, name);
+ fprintf (file, "\n");
+
+ ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
+}
+
+/* Add data area to the given declaration if a ghs data area pragma is
+ currently in effect (#pragma ghs startXXX/endXXX). */
+static void
+v850_insert_attributes (decl, attr_ptr)
+ tree decl;
+ tree *attr_ptr ATTRIBUTE_UNUSED;
+{
+ if (data_area_stack
+ && data_area_stack->data_area
+ && current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
+ && v850_get_data_area (decl) == DATA_AREA_NORMAL)
+ v850_set_data_area (decl, data_area_stack->data_area);
+
+ /* Initialise the default names of the v850 specific sections,
+ if this has not been done before. */
+
+ if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
+ {
+ GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
+ = build_string (sizeof (".sdata")-1, ".sdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
+ = build_string (sizeof (".rosdata")-1, ".rosdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
+ = build_string (sizeof (".tdata")-1, ".tdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
+ = build_string (sizeof (".zdata")-1, ".zdata");
+
+ GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
+ = build_string (sizeof (".rozdata")-1, ".rozdata");
+ }
+
+ if (current_function_decl == NULL_TREE
+ && (TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == CONST_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
+ && !DECL_SECTION_NAME (decl))
+ {
+ enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
+ tree chosen_section;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ kind = GHS_SECTION_KIND_TEXT;
+ else
+ {
+ /* First choose a section kind based on the data area of the decl. */
+ switch (v850_get_data_area (decl))
+ {
+ default:
+ abort ();
+
+ case DATA_AREA_SDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROSDATA
+ : GHS_SECTION_KIND_SDATA);
+ break;
+
+ case DATA_AREA_TDA:
+ kind = GHS_SECTION_KIND_TDATA;
+ break;
+
+ case DATA_AREA_ZDA:
+ kind = ((TREE_READONLY (decl))
+ ? GHS_SECTION_KIND_ROZDATA
+ : GHS_SECTION_KIND_ZDATA);
+ break;
+
+ case DATA_AREA_NORMAL: /* default data area */
+ if (TREE_READONLY (decl))
+ kind = GHS_SECTION_KIND_RODATA;
+ else if (DECL_INITIAL (decl))
+ kind = GHS_SECTION_KIND_DATA;
+ else
+ kind = GHS_SECTION_KIND_BSS;
+ }
+ }
+
+ /* Now, if the section kind has been explicitly renamed,
+ then attach a section attribute. */
+ chosen_section = GHS_current_section_names [(int) kind];
+
+ /* Otherwise, if this kind of section needs an explicit section
+ attribute, then also attach one. */
+ if (chosen_section == NULL)
+ chosen_section = GHS_default_section_names [(int) kind];
+
+ if (chosen_section)
+ {
+ /* Only set the section name if specified by a pragma, because
+ otherwise it will force those variables to get allocated storage
+ in this module, rather than by the linker. */
+ DECL_SECTION_NAME (decl) = chosen_section;
+ }
+ }
+}
+\f
+/* Implement `va_arg'. */
+
+rtx
+v850_va_arg (valist, type)
+ tree valist, type;
+{
+ HOST_WIDE_INT size, rsize;
+ tree addr, incr;
+ rtx addr_rtx;
+ int indirect;
+
+ /* Round up sizeof(type) to a word. */
+ size = int_size_in_bytes (type);
+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+ indirect = 0;
+
+ if (size > 8)
+ {
+ size = rsize = UNITS_PER_WORD;
+ indirect = 1;
+ }
+
+ addr = save_expr (valist);
+ incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
+ build_int_2 (rsize, 0)));
+
+ incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
+ TREE_SIDE_EFFECTS (incr) = 1;
+ expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
+
+ if (indirect)
+ {
+ addr_rtx = force_reg (Pmode, addr_rtx);
+ addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
+ set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+ }
+
+ return addr_rtx;
+}
+\f
+/* Return an RTX indicating where the return address to the
+ calling function can be found. */
+
+rtx
+v850_return_addr (count)
+ int count;
+{
+ if (count != 0)
+ return const0_rtx;
+
+ return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
+}
+\f
+static void
+v850_select_section (exp, reloc, align)
+ tree exp;
+ int reloc;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ int is_const;
+ if (!TREE_READONLY (exp)
+ || TREE_SIDE_EFFECTS (exp)
+ || !DECL_INITIAL (exp)
+ || (DECL_INITIAL (exp) != error_mark_node
+ && !TREE_CONSTANT (DECL_INITIAL (exp))))
+ is_const = FALSE;
+ else
+ is_const = TRUE;
+
+ switch (v850_get_data_area (exp))
+ {
+ case DATA_AREA_ZDA:
+ if (is_const)
+ rozdata_section ();
+ else
+ zdata_section ();
+ break;
+
+ case DATA_AREA_TDA:
+ tdata_section ();
+ break;
+
+ case DATA_AREA_SDA:
+ if (is_const)
+ rosdata_section ();
+ else
+ sdata_section ();
+ break;
+
+ default:
+ if (is_const)
+ readonly_data_section ();
+ else
+ data_section ();
+ break;
+ }
+ }
+ else if (TREE_CODE (exp) == STRING_CST)
+ {
+ if (! flag_writable_strings)
+ readonly_data_section ();
+ else
+ data_section ();
+ }
+ else
+ readonly_data_section ();
+}