summaryrefslogtreecommitdiff
path: root/gcc/config/v850/v850.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/v850/v850.c')
-rwxr-xr-xgcc/config/v850/v850.c3673
1 files changed, 0 insertions, 3673 deletions
diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c
deleted file mode 100755
index 60cb9e1..0000000
--- a/gcc/config/v850/v850.c
+++ /dev/null
@@ -1,3673 +0,0 @@
-/* Subroutines for insn-output.c for NEC V850 series
- Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
- Contributed by Jeff Law (law@cygnus.com).
-
-This file is part of GNU CC.
-
-GNU CC 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 2, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#include <stdio.h>
-#include <ctype.h>
-#include "config.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 "obstack.h"
-#include "toplev.h"
-
-#ifndef streq
-#define streq(a,b) (strcmp (a, b) == 0)
-#endif
-
-/* Function prototypes that cannot exist in v850.h due to dependency
- compilcations. */
-extern rtx function_arg
- PROTO ((CUMULATIVE_ARGS *, enum machine_mode, tree, int));
-extern int function_arg_partial_nregs
- PROTO ((CUMULATIVE_ARGS *, enum machine_mode, tree, int));
-extern void asm_file_start PROTO ((FILE *));
-extern void print_operand PROTO ((FILE *, rtx, int ));
-extern void print_operand_address PROTO ((FILE *, rtx));
-extern void v850_output_aligned_bss
- PROTO ((FILE *, tree, char *, int, int));
-extern void v850_output_common
- PROTO ((FILE *, tree, char *, int, int));
-extern void v850_output_local
- PROTO ((FILE *, tree, char *, int, int));
-extern int const_costs PROTO ((rtx, enum rtx_code));
-extern char * output_move_double PROTO ((rtx *));
-extern char * output_move_single PROTO ((rtx *));
-extern int ep_memory_operand
- PROTO ((rtx, enum machine_mode, int));
-extern int reg_or_0_operand PROTO ((rtx, enum machine_mode));
-extern int reg_or_int5_operand PROTO ((rtx, enum machine_mode));
-extern int call_address_operand PROTO ((rtx, enum machine_mode));
-extern int movsi_source_operand PROTO ((rtx, enum machine_mode));
-extern int power_of_two_operand PROTO ((rtx, enum machine_mode));
-extern int not_power_of_two_operand PROTO ((rtx, enum machine_mode));
-extern int special_symbolref_operand PROTO ((rtx, enum machine_mode));
-extern void v850_reorg PROTO ((rtx));
-extern void notice_update_cc PROTO ((rtx, rtx));
-extern int v850_valid_machine_decl_attribute
- PROTO ((tree, tree, tree));
-extern int v850_interrupt_function_p PROTO ((tree));
-extern int pattern_is_ok_for_prologue PROTO ((rtx, enum machine_mode));
-extern int pattern_is_ok_for_epilogue PROTO ((rtx, enum machine_mode));
-extern int register_is_ok_for_epilogue PROTO ((rtx, enum machine_mode));
-extern char * construct_save_jarl PROTO ((rtx));
-extern char * construct_restore_jr PROTO ((rtx));
-extern void v850_encode_data_area PROTO ((tree));
-extern void v850_set_default_decl_attr PROTO ((tree));
-
-/* Function prototypes for stupid compilers: */
-static void const_double_split
- PROTO ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
-static int const_costs_int PROTO ((HOST_WIDE_INT, int));
-static void substitute_ep_register PROTO ((rtx, rtx, int, int, rtx *, rtx *));
-static int push_data_area PROTO ((v850_data_area));
-static int pop_data_area PROTO ((v850_data_area));
-static int parse_ghs_pragma_token PROTO ((char *));
-static int ep_memory_offset PROTO ((enum machine_mode, int));
-static int mark_current_function_as_interrupt PROTO ((void));
-static void v850_set_data_area PROTO ((tree, v850_data_area));
-/* CYGNUS LOCAL v850e */
-extern int pattern_is_ok_for_prepare PROTO ((rtx, enum machine_mode));
-extern int pattern_is_ok_for_dispose PROTO ((rtx, enum machine_mode));
-extern char * construct_dispose_instruction PROTO ((rtx));
-extern char * construct_prepare_instruction PROTO ((rtx));
-/* END CYGNUS LOCAL */
-
-/* True if the current function has anonymous arguments. */
-int current_function_anonymous_args;
-
-/* Information about the various small memory areas. */
-struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
-{
- /* name value max physical max */
- { "tda", (char *)0, 0, 256 },
- { "sda", (char *)0, 0, 65536 },
- { "zda", (char *)0, 0, 32768 },
-};
-
-/* True if we don't need to check any more if the current
- 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;
-
-
-/* Sometimes certain combinations of command options do not make
- sense on a particular target machine. You can define a macro
- `OVERRIDE_OPTIONS' to take account of this. This macro, if
- defined, is executed once just after all the command options have
- been parsed.
-
- Don't use this macro to turn on various extra optimizations for
- `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
-
-void
-override_options ()
-{
- int i;
- extern int atoi PROTO ((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.",
- 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.",
- small_memory[i].name,
- small_memory[i].value);
- }
- }
- }
-/* CYGNUS LOCAL v850e */
-#ifdef MASK_US_BIT_SET
- /* Make sure that the US_BIT_SET mask has been correctly initialised. */
- if ((target_flags & MASK_US_MASK_SET) == 0)
- {
- if (TARGET_V850EA)
- target_flags |= (MASK_US_MASK_SET | MASK_US_BIT_SET);
- else
- {
- target_flags |= MASK_US_MASK_SET;
- target_flags &= ~MASK_US_BIT_SET;
- }
- }
-#endif
-/* END CYGNUS LOCAL */
-}
-
-
-/* Output assembly code for the start of the file. */
-
-void
-asm_file_start (file)
- FILE *file;
-{
- output_file_directive (file, main_input_filename);
-}
-
-
-/* Return an RTX to represent where a value with mode MODE will be returned
- from a function. If the result is 0, the argument is pushed. */
-
-rtx
-function_arg (cum, mode, type, named)
- CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
- tree type;
- int named;
-{
- rtx result = 0;
- int size, align;
-
- if (TARGET_GHS && !named)
- return NULL_RTX;
-
- if (mode == BLKmode)
- size = int_size_in_bytes (type);
- else
- size = GET_MODE_SIZE (mode);
-
- if (type)
- align = TYPE_ALIGN (type) / BITS_PER_UNIT;
- else
- align = size;
-
- cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
-
- if (cum->nbytes > 4 * UNITS_PER_WORD)
- return 0;
-
- if (type == NULL_TREE
- && cum->nbytes + size > 4 * UNITS_PER_WORD)
- return 0;
-
- switch (cum->nbytes / UNITS_PER_WORD)
- {
- case 0:
- result = gen_rtx (REG, mode, 6);
- break;
- case 1:
- result = gen_rtx (REG, mode, 7);
- break;
- case 2:
- result = gen_rtx (REG, mode, 8);
- break;
- case 3:
- result = gen_rtx (REG, mode, 9);
- break;
- default:
- result = 0;
- }
-
- return result;
-}
-
-
-/* Return the number of words which must be put into registers
- for values which are part in registers and part in memory. */
-
-int
-function_arg_partial_nregs (cum, mode, type, named)
- CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
- tree type;
- int named;
-{
- int size, align;
-
- if (TARGET_GHS && !named)
- return 0;
-
- if (mode == BLKmode)
- size = int_size_in_bytes (type);
- else
- size = GET_MODE_SIZE (mode);
-
- if (type)
- align = TYPE_ALIGN (type) / BITS_PER_UNIT;
- else
- align = size;
-
- cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
-
- if (cum->nbytes > 4 * UNITS_PER_WORD)
- return 0;
-
- if (cum->nbytes + size <= 4 * UNITS_PER_WORD)
- return 0;
-
- if (type == NULL_TREE
- && cum->nbytes + size > 4 * UNITS_PER_WORD)
- return 0;
-
- return (4 * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;
-}
-
-
-/* Return the high and low words of a CONST_DOUBLE */
-
-static void
-const_double_split (x, p_high, p_low)
- rtx x;
- HOST_WIDE_INT *p_high;
- HOST_WIDE_INT *p_low;
-{
- if (GET_CODE (x) == CONST_DOUBLE)
- {
- long t[2];
- REAL_VALUE_TYPE rv;
-
- switch (GET_MODE (x))
- {
- case DFmode:
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, t);
- *p_high = t[1]; /* since v850 is little endian */
- *p_low = t[0]; /* high is second word */
- return;
-
- case SFmode:
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, *p_high);
- *p_low = 0;
- return;
-
- case VOIDmode:
- case DImode:
- *p_high = CONST_DOUBLE_HIGH (x);
- *p_low = CONST_DOUBLE_LOW (x);
- return;
-
- default:
- break;
- }
- }
-
- fatal_insn ("const_double_split got a bad insn:", x);
-}
-
-
-/* Return the cost of the rtx R with code CODE. */
-
-static int
-const_costs_int (value, zero_cost)
- HOST_WIDE_INT value;
- int zero_cost;
-{
- if (CONST_OK_FOR_I (value))
- return zero_cost;
- else if (CONST_OK_FOR_J (value))
- return 1;
- else if (CONST_OK_FOR_K (value))
- return 2;
- else
- return 4;
-}
-
-int
-const_costs (r, c)
- rtx r;
- enum rtx_code c;
-{
- HOST_WIDE_INT high, low;
-
- switch (c)
- {
- case CONST_INT:
- return const_costs_int (INTVAL (r), 0);
-
- case CONST_DOUBLE:
- const_double_split (r, &high, &low);
- if (GET_MODE (r) == SFmode)
- return const_costs_int (high, 1);
- else
- return const_costs_int (high, 1) + const_costs_int (low, 1);
-
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST:
- return 2;
-
- case HIGH:
- return 1;
-
- default:
- return 4;
- }
-}
-
-
-/* Print operand X using operand code CODE to assembly language output file
- FILE. */
-
-void
-print_operand (file, x, code)
- FILE *file;
- rtx x;
- int code;
-{
- HOST_WIDE_INT high, low;
-
- 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':
- case 'C':
- switch ((code == 'B' || code == 'C')
- ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
- {
- case NE:
- if (code == 'c' || code == 'C')
- fprintf (file, "nz");
- else
- fprintf (file, "ne");
- break;
- case EQ:
- if (code == 'c' || code == 'C')
- fprintf (file, "z");
- else
- fprintf (file, "e");
- break;
- case GE:
- fprintf (file, "ge");
- break;
- case GT:
- fprintf (file, "gt");
- break;
- case LE:
- fprintf (file, "le");
- break;
- case LT:
- fprintf (file, "lt");
- break;
- case GEU:
- fprintf (file, "nl");
- break;
- case GTU:
- fprintf (file, "h");
- break;
- case LEU:
- fprintf (file, "nh");
- break;
- case LTU:
- fprintf (file, "l");
- break;
- default:
- abort ();
- }
- break;
- case 'F': /* high word of CONST_DOUBLE */
- if (GET_CODE (x) == CONST_INT)
- fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
- else if (GET_CODE (x) == CONST_DOUBLE)
- {
- const_double_split (x, &high, &low);
- fprintf (file, "%ld", (long) high);
- }
- else
- abort ();
- break;
- case 'G': /* low word of CONST_DOUBLE */
- if (GET_CODE (x) == CONST_INT)
- fprintf (file, "%ld", (long) INTVAL (x));
- else if (GET_CODE (x) == CONST_DOUBLE)
- {
- const_double_split (x, &high, &low);
- fprintf (file, "%ld", (long) low);
- }
- else
- abort ();
- break;
- case 'L':
- fprintf (file, "%d\n", INTVAL (x) & 0xffff);
- break;
- case 'M':
- fprintf (file, "%d", exact_log2 (INTVAL (x)));
- break;
- case 'O':
- if (special_symbolref_operand (x, VOIDmode))
- {
- char* name;
-
- if (GET_CODE (x) == SYMBOL_REF)
- name = XSTR (x, 0);
- else if (GET_CODE (x) == CONST)
- name = XSTR (XEXP (XEXP (x, 0), 0), 0);
- else
- abort ();
-
- if (ZDA_NAME_P (name))
- fprintf (file, "zdaoff");
- else if (SDA_NAME_P (name))
- fprintf (file, "sdaoff");
- else if (TDA_NAME_P (name))
- fprintf (file, "tdaoff");
- else
- abort ();
- }
- else
- abort ();
- break;
- case 'P':
- if (special_symbolref_operand (x, VOIDmode))
- output_addr_const (file, x);
- else
- abort ();
- break;
- case 'Q':
- if (special_symbolref_operand (x, VOIDmode))
- {
- char* name;
-
- if (GET_CODE (x) == SYMBOL_REF)
- name = XSTR (x, 0);
- else if (GET_CODE (x) == CONST)
- name = XSTR (XEXP (XEXP (x, 0), 0), 0);
- else
- abort ();
-
- if (ZDA_NAME_P (name))
- fprintf (file, "r0");
- else if (SDA_NAME_P (name))
- fprintf (file, "gp");
- else if (TDA_NAME_P (name))
- fprintf (file, "ep");
- else
- abort ();
- }
- else
- 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;
-
- default:
- break;
- }
- break;
- case 'S':
- {
- /* 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);
-
- break;
- }
- case 'T':
- {
- /* Like an 'S' operand above, but for unsigned loads only. */
- if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), TRUE))
- fputs ("s", file);
-
- break;
- }
- case 'W': /* print the instruction suffix */
- switch (GET_MODE (x))
- {
- default:
- abort ();
-
- case QImode: fputs (".b", file); break;
- case HImode: fputs (".h", file); break;
- case SImode: fputs (".w", file); break;
- case SFmode: fputs (".w", file); break;
- }
- break;
- 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)));
- else
- output_address (XEXP (x, 0));
- break;
-
- case REG:
- fputs (reg_names[REGNO (x)], file);
- break;
- case SUBREG:
- fputs (reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)], file);
- break;
- case CONST_INT:
- case SYMBOL_REF:
- case CONST:
- case LABEL_REF:
- case CODE_LABEL:
- print_operand_address (file, x);
- break;
- default:
- abort ();
- }
- break;
-
- }
-}
-
-
-/* Output assembly language output for the address ADDR to FILE. */
-
-void
-print_operand_address (file, addr)
- FILE *file;
- rtx addr;
-{
- switch (GET_CODE (addr))
- {
- case REG:
- fprintf (file, "0[");
- print_operand (file, addr, 0);
- fprintf (file, "]");
- break;
- case LO_SUM:
- if (GET_CODE (XEXP (addr, 0)) == REG)
- {
- /* reg,foo */
- fprintf (file, "lo(");
- print_operand (file, XEXP (addr, 1), 0);
- fprintf (file, ")[");
- print_operand (file, XEXP (addr, 0), 0);
- fprintf (file, "]");
- }
- break;
- case PLUS:
- if (GET_CODE (XEXP (addr, 0)) == REG
- || GET_CODE (XEXP (addr, 0)) == SUBREG)
- {
- /* reg,foo */
- print_operand (file, XEXP (addr, 1), 0);
- fprintf (file, "[");
- print_operand (file, XEXP (addr, 0), 0);
- fprintf (file, "]");
- }
- else
- {
- print_operand (file, XEXP (addr, 0), 0);
- fprintf (file, "+");
- print_operand (file, XEXP (addr, 1), 0);
- }
- break;
- case SYMBOL_REF:
- if (ENCODED_NAME_P (XSTR (addr, 0)))
- {
- char* name = XSTR (addr, 0);
- char* off_name;
- char* reg_name;
-
- if (ZDA_NAME_P (name))
- {
- off_name = "zdaoff";
- reg_name = "r0";
- }
- else if (SDA_NAME_P (name))
- {
- off_name = "sdaoff";
- reg_name = "gp";
- }
- else if (TDA_NAME_P (name))
- {
- off_name = "tdaoff";
- reg_name = "ep";
- }
- else
- abort ();
-
- fprintf (file, "%s(", off_name);
- output_addr_const (file, addr);
- fprintf (file, ")[%s]", reg_name);
- }
- else
- output_addr_const (file, addr);
- break;
- case CONST:
- if (special_symbolref_operand (addr, VOIDmode))
- {
- char* name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
- char* off_name;
- char* reg_name;
-
- if (ZDA_NAME_P (name))
- {
- off_name = "zdaoff";
- reg_name = "r0";
- }
- else if (SDA_NAME_P (name))
- {
- off_name = "sdaoff";
- reg_name = "gp";
- }
- else if (TDA_NAME_P (name))
- {
- off_name = "tdaoff";
- reg_name = "ep";
- }
- else
- abort ();
-
- fprintf (file, "%s(", off_name);
- output_addr_const (file, addr);
- fprintf (file, ")[%s]", reg_name);
- }
- else
- output_addr_const (file, addr);
- break;
- default:
- output_addr_const (file, addr);
- break;
- }
-}
-
-
-/* Return appropriate code to load up a 1, 2, or 4 integer/floating
- point value. */
-
-char *
-output_move_single (operands)
- rtx *operands;
-{
- rtx dst = operands[0];
- rtx src = operands[1];
-
- if (REG_P (dst))
- {
- if (REG_P (src))
- return "mov %1,%0";
-
- else if (GET_CODE (src) == CONST_INT)
- {
- HOST_WIDE_INT value = INTVAL (src);
-
- if (CONST_OK_FOR_J (value)) /* signed 5 bit immediate */
- return "mov %1,%0";
-
- else if (CONST_OK_FOR_K (value)) /* signed 16 bit immediate */
- return "movea lo(%1),%.,%0";
-
- else if (CONST_OK_FOR_L (value)) /* upper 16 bits were set */
- return "movhi hi(%1),%.,%0";
-
- else /* random constant */
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E)
- return "mov %1,%0";
- else
-/* END CYGNUS LOCAL */
- return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
- }
-
- else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
- {
- HOST_WIDE_INT high, low;
-
- const_double_split (src, &high, &low);
- if (CONST_OK_FOR_J (high)) /* signed 5 bit immediate */
- return "mov %F1,%0";
-
- else if (CONST_OK_FOR_K (high)) /* signed 16 bit immediate */
- return "movea lo(%F1),%.,%0";
-
- else if (CONST_OK_FOR_L (high)) /* upper 16 bits were set */
- return "movhi hi(%F1),%.,%0";
-
- else /* random constant */
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E)
- return "mov %F1,%0";
- else
-/* END CYGNUS LOCAL */
- return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0";
- }
-
- else if (GET_CODE (src) == MEM)
- return "%S1ld%W1 %1,%0";
-
- else if (special_symbolref_operand (src, VOIDmode))
- return "movea %O1(%P1),%Q1,%0";
-
- else if (GET_CODE (src) == LABEL_REF
- || GET_CODE (src) == SYMBOL_REF
- || GET_CODE (src) == CONST)
- {
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E)
- return "mov hilo(%1),%0";
- else
-/* END CYGNUS LOCAL */
- return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
- }
-
- else if (GET_CODE (src) == HIGH)
- return "movhi hi(%1),%.,%0";
-
- else if (GET_CODE (src) == LO_SUM)
- {
- operands[2] = XEXP (src, 0);
- operands[3] = XEXP (src, 1);
- return "movea lo(%3),%2,%0";
- }
- }
-
- else if (GET_CODE (dst) == MEM)
- {
- if (REG_P (src))
- return "%S0st%W0 %1,%0";
-
- else if (GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
- return "%S0st%W0 %.,%0";
-
- else if (GET_CODE (src) == CONST_DOUBLE
- && CONST0_RTX (GET_MODE (dst)) == src)
- return "%S0st%W0 %.,%0";
- }
-
- fatal_insn ("output_move_single:", gen_rtx (SET, VOIDmode, dst, src));
- return "";
-}
-
-
-/* Return appropriate code to load up an 8 byte integer or
- floating point value */
-
-char *
-output_move_double (operands)
- rtx *operands;
-{
- enum machine_mode mode = GET_MODE (operands[0]);
- rtx dst = operands[0];
- rtx src = operands[1];
-
- if (register_operand (dst, mode)
- && register_operand (src, mode))
- {
- if (REGNO (src) + 1 == REGNO (dst))
- return "mov %R1,%R0\n\tmov %1,%0";
- else
- return "mov %1,%0\n\tmov %R1,%R0";
- }
-
- /* Storing 0 */
- if (GET_CODE (dst) == MEM
- && ((GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
- || (GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src))))
- return "st.w %.,%0\n\tst.w %.,%R0";
-
- if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
- {
- HOST_WIDE_INT high_low[2];
- int i;
- rtx xop[10];
-
- if (GET_CODE (src) == CONST_DOUBLE)
- const_double_split (src, &high_low[1], &high_low[0]);
- else
- {
- high_low[0] = INTVAL (src);
- high_low[1] = (INTVAL (src) >= 0) ? 0 : -1;
- }
-
- for (i = 0; i < 2; 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);
- }
-
- return "";
- }
-
- if (GET_CODE (src) == MEM)
- {
- int ptrreg = -1;
- int dreg = REGNO (dst);
- rtx inside = XEXP (src, 0);
-
- if (GET_CODE (inside) == REG)
- ptrreg = REGNO (inside);
- else if (GET_CODE (inside) == SUBREG)
- ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside);
- else if (GET_CODE (inside) == PLUS)
- ptrreg = REGNO (XEXP (inside, 0));
- else if (GET_CODE (inside) == LO_SUM)
- ptrreg = REGNO (XEXP (inside, 0));
-
- if (dreg == ptrreg)
- return "ld.w %R1,%R0\n\tld.w %1,%0";
- }
-
- if (GET_CODE (src) == MEM)
- return "ld.w %1,%0\n\tld.w %R1,%R0";
-
- if (GET_CODE (dst) == MEM)
- return "st.w %1,%0\n\tst.w %R1,%R0";
-
- return "mov %1,%0\n\tmov %R1,%R0";
-}
-
-
-/* Return maximum offset supported for a short EP memory reference of mode
- MODE and signedness UNSIGNEDP. */
-
-static int
-ep_memory_offset (mode, unsignedp)
- enum machine_mode mode;
- int ATTRIBUTE_UNUSED unsignedp;
-{
- int max_offset = 0;
-
- switch (mode)
- {
- case QImode:
-/* CYGNUS LOCAL v850e */
- if (TARGET_SMALL_SLD)
- {
- max_offset = (1 << 4);
- break;
- }
-/* END CYGNUS LOCAL */
- max_offset = (1 << 7);
-
-/* CYGNUS LOCAL v850e */
-#ifdef TARGET_US_BIT_SET
- if (TARGET_V850E
- && ( ( unsignedp && ! TARGET_US_BIT_SET)
- || (! unsignedp && TARGET_US_BIT_SET)))
- max_offset = (1 << 4);
-#else
- if (TARGET_V850E && unsignedp)
- max_offset = (1 << 4);
-#endif
-/* END CYGNUS LOCAL */
- break;
-
- case HImode:
-/* CYGNUS LOCAL v850e */
- if (TARGET_SMALL_SLD)
- {
- max_offset = (1 << 5);
- break;
- }
-/* END CYGNUS LOCAL v850e */
- max_offset = (1 << 8);
-
-/* CYGNUS LOCAL v850e */
-#ifdef TARGET_US_BIT_SET
- if (TARGET_V850E
- && (( unsignedp && ! TARGET_US_BIT_SET)
- || (! unsignedp && TARGET_US_BIT_SET)))
- max_offset = (1 << 5);
-#else
- if (TARGET_V850E && unsignedp)
- max_offset = (1 << 5);
-#endif
-/* END CYGNUS LOCAL */
- break;
-
- case SImode:
- case SFmode:
- max_offset = (1 << 8);
- 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);
-
- switch (GET_CODE (addr))
- {
- default:
- break;
-
- case SYMBOL_REF:
- return TDA_NAME_P (XSTR (addr, 0));
-
- case REG:
- return REGNO (addr) == EP_REGNUM;
-
- case PLUS:
- op0 = 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)
- return TRUE;
-
- if (GET_CODE (op0) == SYMBOL_REF && TDA_NAME_P (XSTR (op0, 0)))
- return TRUE;
- }
- break;
- }
-
- return FALSE;
-}
-
-/* Return true if OP is either a register or 0 */
-
-int
-reg_or_0_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) == CONST_INT)
- return INTVAL (op) == 0;
-
- else if (GET_CODE (op) == CONST_DOUBLE)
- return CONST_DOUBLE_OK_FOR_G (op);
-
- else
- return register_operand (op, mode);
-}
-
-/* Return true if OP is either a register or a signed five bit integer */
-
-int
-reg_or_int5_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- if (GET_CODE (op) == CONST_INT)
- return CONST_OK_FOR_J (INTVAL (op));
-
- 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 ATTRIBUTE_UNUSED mode;
-{
- /* Only registers are valid call operands if TARGET_LONG_CALLS. */
- if (TARGET_LONG_CALLS)
- return GET_CODE (op) == REG;
- return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
-}
-
-int
-special_symbolref_operand (op, mode)
- rtx op;
- enum machine_mode ATTRIBUTE_UNUSED mode;
-{
- if (GET_CODE (op) == SYMBOL_REF)
- return ENCODED_NAME_P (XSTR (op, 0));
-
- else if (GET_CODE (op) == CONST)
- return (GET_CODE (XEXP (op, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
- && ENCODED_NAME_P (XSTR (XEXP (XEXP (op, 0), 0), 0))
- && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
- && CONST_OK_FOR_K (INTVAL (XEXP (XEXP (op, 0), 1))));
-
- return FALSE;
-}
-
-int
-movsi_source_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- /* Some constants, as well as symbolic operands
- 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))
- || CONST_OK_FOR_L (INTVAL (op)))))
- return special_symbolref_operand (op, mode);
- else
- return general_operand (op, mode);
-}
-
-int
-power_of_two_operand (op, mode)
- rtx op;
- enum machine_mode ATTRIBUTE_UNUSED mode;
-{
- if (GET_CODE (op) != CONST_INT)
- return 0;
-
- if (exact_log2 (INTVAL (op)) == -1)
- return 0;
- return 1;
-}
-
-int
-not_power_of_two_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- unsigned int mask;
-
- if (mode == QImode)
- mask = 0xff;
- else if (mode == HImode)
- mask = 0xffff;
- else if (mode == SImode)
- mask = 0xffffffff;
- else
- return 0;
-
- if (GET_CODE (op) != CONST_INT)
- return 0;
-
- if (exact_log2 (~INTVAL (op) & mask) == -1)
- return 0;
- return 1;
-}
-
-
-/* Substitute memory references involving a pointer, to use the ep pointer,
- taking care to save and preserve the ep. */
-
-static void
-substitute_ep_register (first_insn, last_insn, uses, regno, p_r1, p_ep)
- rtx first_insn;
- rtx last_insn;
- int uses;
- int regno;
- rtx *p_r1;
- rtx *p_ep;
-{
- rtx reg = gen_rtx (REG, Pmode, regno);
- rtx insn;
-
- if (!*p_r1)
- {
- regs_ever_live[1] = 1;
- *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",
- 2 * (uses - 3), uses, reg_names[regno],
- IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
- INSN_UID (first_insn), INSN_UID (last_insn));
-
- if (GET_CODE (first_insn) == NOTE)
- first_insn = next_nonnote_insn (first_insn);
-
- last_insn = next_nonnote_insn (last_insn);
- for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == INSN)
- {
- rtx pattern = single_set (insn);
-
- /* Replace the memory references. */
- 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)
- p_mem = (rtx *)0;
-
- else if (GET_CODE (SET_DEST (pattern)) == MEM)
- p_mem = &SET_DEST (pattern);
-
- else if (GET_CODE (SET_SRC (pattern)) == MEM)
- p_mem = &SET_SRC (pattern);
-
- /* CYGNUS LOCAL v850e */
- else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND
- && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
- p_mem = &XEXP (SET_SRC (pattern), 0);
-
- else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND
- && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
- {
- p_mem = &XEXP (SET_SRC (pattern), 0);
- unsignedp = TRUE;
- }
- /* END CYGNUS LOCAL */
-
- else
- p_mem = (rtx *)0;
-
- if (p_mem)
- {
- rtx addr = XEXP (*p_mem, 0);
-
- if (GET_CODE (addr) == REG && REGNO (addr) == 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
- && GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((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)));
- }
- }
- }
- }
-
- /* Optimize back to back cases of ep <- r1 & r1 <- ep. */
- insn = prev_nonnote_insn (first_insn);
- if (insn && GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == *p_ep
- && 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_ep, reg), first_insn);
- emit_insn_before (gen_rtx (SET, Pmode, *p_ep, *p_r1), last_insn);
-}
-
-
-/* In rare cases, correct code generation requires extra machine
- dependent processing between the second jump optimization pass and
- delayed branch scheduling. On those machines, define this macro
- 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 */
-
-void v850_reorg (start_insn)
- rtx start_insn;
-{
- struct
- {
- int uses;
- rtx first_insn;
- rtx last_insn;
- }
- regs[FIRST_PSEUDO_REGISTER];
-
- int i;
- int use_ep = FALSE;
- rtx r1 = NULL_RTX;
- rtx ep = NULL_RTX;
- rtx insn;
- rtx pattern;
-
- /* If not ep mode, just return now */
- if (!TARGET_EP)
- return;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- regs[i].uses = 0;
- regs[i].first_insn = NULL_RTX;
- regs[i].last_insn = NULL_RTX;
- }
-
- for (insn = start_insn; insn != NULL_RTX; insn = NEXT_INSN (insn))
- {
- switch (GET_CODE (insn))
- {
- /* End of basic block */
- default:
- if (!use_ep)
- {
- int max_uses = -1;
- int max_regno = -1;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if (max_uses < regs[i].uses)
- {
- max_uses = regs[i].uses;
- max_regno = i;
- }
- }
-
- if (max_uses > 3)
- substitute_ep_register (regs[max_regno].first_insn,
- regs[max_regno].last_insn,
- max_uses, max_regno, &r1, &ep);
- }
-
- use_ep = FALSE;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- regs[i].uses = 0;
- regs[i].first_insn = NULL_RTX;
- regs[i].last_insn = NULL_RTX;
- }
- break;
-
- case NOTE:
- break;
-
- case INSN:
- pattern = single_set (insn);
-
- /* See if there are any memory references we can shorten */
- if (pattern)
- {
- 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. It is safe to call
- alter_subreg any time after reload. */
- if (GET_CODE (dest) == SUBREG)
- dest = alter_subreg (dest);
- if (GET_CODE (src) == SUBREG)
- src = alter_subreg (src);
-
- if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
- mem = NULL_RTX;
-
- else if (GET_CODE (dest) == MEM)
- mem = dest;
-
- else if (GET_CODE (src) == MEM)
- mem = src;
-
- /* CYGNUS LOCAL v850e */
- else if (GET_CODE (src) == SIGN_EXTEND
- && GET_CODE (XEXP (src, 0)) == MEM)
- mem = XEXP (src, 0);
-
- else if (GET_CODE (src) == ZERO_EXTEND
- && GET_CODE (XEXP (src, 0)) == MEM)
- {
- mem = XEXP (src, 0);
- unsignedp = TRUE;
- }
- /* END CYGNUS LOCAL */
-
- else
- mem = NULL_RTX;
-
- if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
- use_ep = TRUE;
-
- else if (!use_ep && mem
- && GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD)
- {
- rtx addr = XEXP (mem, 0);
- int regno = -1;
- int short_p;
-
- if (GET_CODE (addr) == REG)
- {
- short_p = TRUE;
- regno = REGNO (addr);
- }
-
- else if (GET_CODE (addr) == PLUS
- && GET_CODE (XEXP (addr, 0)) == REG
- && GET_CODE (XEXP (addr, 1)) == CONST_INT
- && ((INTVAL (XEXP (addr, 1)))
- < ep_memory_offset (GET_MODE (mem), unsignedp))
- && ((INTVAL (XEXP (addr, 1))) >= 0))
- {
- short_p = TRUE;
- regno = REGNO (XEXP (addr, 0));
- }
-
- else
- short_p = FALSE;
-
- if (short_p)
- {
- regs[regno].uses++;
- regs[regno].last_insn = insn;
- if (!regs[regno].first_insn)
- regs[regno].first_insn = insn;
- }
- }
-
- /* Loading up a register in the basic block zaps any savings
- for the register */
- if (GET_CODE (dest) == REG)
- {
- enum machine_mode mode = GET_MODE (dest);
- int regno;
- int endregno;
-
- regno = REGNO (dest);
- endregno = regno + HARD_REGNO_NREGS (regno, mode);
-
- if (!use_ep)
- {
- /* See if we can use the pointer before this
- modification. */
- int max_uses = -1;
- int max_regno = -1;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if (max_uses < regs[i].uses)
- {
- max_uses = regs[i].uses;
- max_regno = i;
- }
- }
-
- if (max_uses > 3
- && max_regno >= regno
- && max_regno < endregno)
- {
- substitute_ep_register (regs[max_regno].first_insn,
- regs[max_regno].last_insn,
- max_uses, max_regno, &r1,
- &ep);
-
- /* Since we made a substitution, zap all remembered
- registers. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- regs[i].uses = 0;
- regs[i].first_insn = NULL_RTX;
- regs[i].last_insn = NULL_RTX;
- }
- }
- }
-
- for (i = regno; i < endregno; i++)
- {
- regs[i].uses = 0;
- regs[i].first_insn = NULL_RTX;
- regs[i].last_insn = NULL_RTX;
- }
- }
- }
- }
- }
-}
-
-
-/* # of registers saved by the interrupt handler. */
-#define INTERRUPT_FIXED_NUM 4
-
-/* # of bytes for registers saved by the interrupt handler. */
-#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)
-
-/* # of registers saved in register parameter area. */
-#define INTERRUPT_REGPARM_NUM 4
-/* # of words saved for other registers. */
-#define INTERRUPT_ALL_SAVE_NUM \
- (30 - INTERRUPT_FIXED_NUM + INTERRUPT_REGPARM_NUM)
-
-#define INTERRUPT_ALL_SAVE_SIZE (4 * INTERRUPT_ALL_SAVE_NUM)
-
-int
-compute_register_save_size (p_reg_saved)
- long *p_reg_saved;
-{
- int size = 0;
- int i;
- int interrupt_handler = v850_interrupt_function_p (current_function_decl);
- 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 [LINK_POINTER_REGNUM] = call_p = 1;
-
- /* Count space for the register saves. */
- if (interrupt_handler)
- {
- for (i = 0; i <= 31; i++)
- switch (i)
- {
- default:
- if (regs_ever_live[i] || call_p)
- {
- size += 4;
- reg_saved |= 1L << i;
- }
- break;
-
- /* We don't save/restore r0 or the stack pointer */
- case 0:
- case STACK_POINTER_REGNUM:
- break;
-
- /* For registers with fixed use, we save them, set them to the
- appropriate value, and then restore them.
- 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 4: /* gp */
- case 10: /* temp used to call interrupt save/restore */
- case EP_REGNUM: /* ep */
- size += 4;
- break;
- }
- }
- else
- {
- /* 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 if the link
- register is not used, and at least registers r27 - r31 if the
- link register is used (and provided that the function is not an
- interrupt handler). */
-
- if (TARGET_PROLOG_FUNCTION
- && (i == 2 || i >= 20)
- && regs_ever_live[LINK_POINTER_REGNUM] ? (i < 28) : (i < 30))
- {
- 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;
-
- return size;
-}
-
-int
-compute_frame_size (size, p_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);
-}
-
-
-void
-expand_prologue ()
-{
- unsigned int i;
- int offset;
- unsigned int size = get_frame_size ();
- unsigned int actual_fsize;
- unsigned int init_stack_alloc = 0;
- rtx save_regs[32];
- rtx save_all;
- 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, &reg_saved);
-
- /* Save/setup global registers for interrupt functions right now */
- if (interrupt_handler)
- {
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
- emit_insn (gen_save_interrupt_v850e ());
- else
-/* END CYGNUS LOCAL */
- emit_insn (gen_save_interrupt ());
-
- actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
-
- if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
- actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
- }
-
- /* Save arg registers to the stack if necessary. */
- else if (current_function_anonymous_args)
- {
- if (TARGET_PROLOG_FUNCTION)
- {
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
- emit_insn (gen_save_r6_r9_v850e ());
- else
-/* END CYGNUS LOCAL */
- 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));
- offset += 4;
- }
- }
- }
-
- /* 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);
- }
-
- /* If the return pointer is saved, the helper functions also allocate
- 16 bytes of stack for arguments to be saved in. */
- if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
- {
- save_regs[num_save++] = gen_rtx (REG, Pmode, LINK_POINTER_REGNUM);
- default_stack = 16;
- }
-
- /* See if we have an insn that allocates stack space and saves the particular
- registers we want to. */
- save_all = NULL_RTX;
- if (TARGET_PROLOG_FUNCTION && num_save > 0 && actual_fsize >= default_stack)
- {
- int alloc_stack = (4 * num_save) + default_stack;
- int unalloc_stack = actual_fsize - alloc_stack;
- int save_func_len = 4;
- int save_normal_len;
-
- if (unalloc_stack)
- save_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
-
- /* see if we would have used ep to save the stack */
- if (TARGET_EP && num_save > 3 && (unsigned)actual_fsize < 255)
- save_normal_len = (3 * 2) + (2 * num_save);
- else
- save_normal_len = 4 * num_save;
-
- save_normal_len += CONST_OK_FOR_J (actual_fsize) ? 2 : 4;
-
- /* Don't bother checking if we don't actually save any space.
- This happens for instance if one register is saved and additional
- 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)));
-
- if (TARGET_V850)
- {
- XVECEXP (save_all, 0, num_save + 1)
- = 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]);
- offset -= 4;
- }
-
- code = recog (save_all, NULL_RTX, NULL_PTR);
- 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",
- save_normal_len - save_func_len,
- save_normal_len, save_func_len,
- IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
- }
- else
- save_all = NULL_RTX;
- }
- }
-
- /* 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 << LINK_POINTER_REGNUM) & reg_saved) != 0)
- {
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
- emit_insn (gen_save_all_interrupt_v850e ());
- else
-/* END CYGNUS LOCAL */
- emit_insn (gen_save_all_interrupt ());
- }
- else
- {
- /* If the stack is too big, allocate it in chunks so we can do the
- register saves. We use the register save size so we use the ep
- register. */
- if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
- init_stack_alloc = compute_register_save_size (NULL);
- else
- init_stack_alloc = actual_fsize;
-
- /* Save registers at the beginning of the stack frame */
- offset = init_stack_alloc - 4;
-
- if (init_stack_alloc)
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (-init_stack_alloc)));
-
- /* Save the return pointer first. */
- 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)),
- 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)),
- save_regs[i]);
- offset -= 4;
- }
- }
- }
-
- /* Allocate the rest of the stack that was not allocated above (either it is
- > 32K or we just called a function to save the registers and needed more
- stack. */
- if (actual_fsize > init_stack_alloc)
- {
- int diff = actual_fsize - init_stack_alloc;
- 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);
- emit_move_insn (reg, GEN_INT (-diff));
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
- }
- }
-
- /* If we need a frame pointer, set it up now. */
- if (frame_pointer_needed)
- emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
-}
-
-
-void
-expand_epilogue ()
-{
- unsigned int i;
- int offset;
- unsigned int size = get_frame_size ();
- long reg_saved = 0;
- unsigned int actual_fsize = compute_frame_size (size, &reg_saved);
- unsigned int init_stack_free = 0;
- rtx restore_regs[32];
- rtx restore_all;
- unsigned int num_restore;
- unsigned int default_stack;
- int code;
- int interrupt_handler = v850_interrupt_function_p (current_function_decl);
-
- /* Eliminate the initial stack stored by interrupt functions. */
- if (interrupt_handler)
- {
- actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
- if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
- actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
- }
-
- /* Cut off any dynamic stack created. */
- if (frame_pointer_needed)
- emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
-
- /* 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);
- }
-
- /* If the return pointer is saved, the helper functions also allocate
- 16 bytes of stack for arguments to be saved in. */
- if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
- {
- 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
- && !interrupt_handler)
- {
- int alloc_stack = (4 * num_restore) + default_stack;
- int unalloc_stack = actual_fsize - alloc_stack;
- int restore_func_len = 4;
- int restore_normal_len;
-
- 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 */
- if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)
- restore_normal_len = (3 * 2) + (2 * num_restore);
- else
- restore_normal_len = 4 * num_restore;
-
- restore_normal_len += (CONST_OK_FOR_J (actual_fsize) ? 2 : 4) + 2;
-
- /* 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);
- XVECEXP (restore_all, 0, 1)
- = 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)));
- offset -= 4;
- }
-
- code = recog (restore_all, NULL_RTX, NULL_PTR);
- if (code >= 0)
- {
- rtx insn;
-
- actual_fsize -= alloc_stack;
- if (actual_fsize)
- {
- if (CONST_OK_FOR_K (actual_fsize))
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (actual_fsize)));
- else
- {
- 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,
- reg));
- }
- }
-
- insn = emit_jump_insn (restore_all);
- INSN_CODE (insn) = code;
-
- if (TARGET_DEBUG)
- 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)));
- }
- else
- restore_all = NULL_RTX;
- }
- }
-
- /* If no epilog save function is available, restore the registers the
- old fashioned way (one by one). */
- if (!restore_all)
- {
- /* If the stack is large, we need to cut it down in 2 pieces. */
- if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
- init_stack_free = 4 * num_restore;
- 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))
- {
- 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);
- emit_move_insn (reg, GEN_INT (diff));
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- reg));
- }
- }
-
- /* Special case interrupt functions that save all registers
- for a call. */
- if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
- {
-/* CYGNUS LOCAL v850e */
- if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
- emit_insn (gen_restore_all_interrupt_v850e ());
- else
-/* END CYGNUS LOCAL */
- emit_insn (gen_restore_all_interrupt ());
- }
- else
- {
- /* 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]) == LINK_POINTER_REGNUM)
- {
- emit_move_insn (restore_regs[--num_restore],
- 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)));
-
- offset -= 4;
- }
-
- /* Cut back the remainder of the stack. */
- if (init_stack_free)
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (init_stack_free)));
- }
-
- /* And return or use reti for interrupt handlers. */
- if (interrupt_handler)
- emit_jump_insn (gen_restore_interrupt ());
- else if (actual_fsize)
- emit_jump_insn (gen_return_internal ());
- else
- emit_jump_insn (gen_return ());
- }
-
- current_function_anonymous_args = 0;
- v850_interrupt_cache_p = FALSE;
- v850_interrupt_p = FALSE;
-}
-
-
-/* Update the condition code from the insn. */
-
-void
-notice_update_cc (body, insn)
- rtx body;
- rtx insn;
-{
- switch (get_attr_cc (insn))
- {
- case CC_NONE:
- /* Insn does not affect CC at all. */
- break;
-
- 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))
- cc_status.value1 = 0;
- break;
-
- case CC_SET_ZN:
- /* Insn sets the Z,N flags of CC to recog_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];
- break;
-
- case CC_SET_ZNV:
- /* Insn sets the Z,N,V flags of CC to recog_operand[0].
- C is in an unusable state. */
- CC_STATUS_INIT;
- cc_status.flags |= CC_NO_CARRY;
- cc_status.value1 = recog_operand[0];
- break;
-
- case CC_COMPARE:
- /* The insn is a compare instruction. */
- CC_STATUS_INIT;
- cc_status.value1 = SET_SRC (body);
- break;
-
- case CC_CLOBBER:
- /* Insn doesn't leave CC in a usable state. */
- CC_STATUS_INIT;
- break;
- }
-}
-
-/* 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_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
- return DATA_AREA_SDA;
-
- if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
- return DATA_AREA_TDA;
-
- if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
- return DATA_AREA_ZDA;
-
- return DATA_AREA_NORMAL;
-}
-
-/* Store the indicated data area in the decl's attributes. */
-
-static void
-v850_set_data_area (decl, data_area)
- tree decl;
- v850_data_area data_area;
-{
- 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_MACHINE_ATTRIBUTES (decl) = tree_cons
- (name, NULL, DECL_MACHINE_ATTRIBUTES (decl));
-}
-
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ARGS are the arguments supplied with ATTR. */
-
-int
-v850_valid_machine_decl_attribute (decl, attr, args)
- tree decl;
- tree attr;
- tree args;
-{
- v850_data_area data_area;
- v850_data_area area;
-
- if (args != NULL_TREE)
- return 0;
-
- if (is_attribute_p ("interrupt_handler", attr)
- || is_attribute_p ("interrupt", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
-
- /* Implement data area attribute. */
- if (is_attribute_p ("sda", attr))
- data_area = DATA_AREA_SDA;
- else if (is_attribute_p ("tda", attr))
- data_area = DATA_AREA_TDA;
- else if (is_attribute_p ("zda", attr))
- data_area = DATA_AREA_ZDA;
- else
- return 0;
-
- 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");
-
- /* Drop through. */
-
- 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");
-
- return 1;
-
- default:
- break;
- }
-
- return 0;
-}
-
-
-/* Return nonzero if FUNC is an interrupt function as specified
- by the "interrupt" attribute. */
-
-int
-v850_interrupt_function_p (func)
- tree func;
-{
- tree a;
- int ret = 0;
-
- if (v850_interrupt_cache_p)
- return v850_interrupt_p;
-
- if (TREE_CODE (func) != FUNCTION_DECL)
- return 0;
-
- a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
- if (a != NULL_TREE)
- ret = 1;
-
- else
- {
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
- ret = a != NULL_TREE;
- }
-
- /* Its not safe to trust global variables until after function inlining has
- been done. */
- if (reload_completed | reload_in_progress)
- v850_interrupt_p = ret;
-
- return ret;
-}
-
-
-extern struct obstack * saveable_obstack;
-
-void
-v850_encode_data_area (decl)
- tree decl;
-{
- 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))
- {
- 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 = obstack_alloc (saveable_obstack, 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) = newstr;
-}
-
-/* Return true if the given RTX is a register which can be restored
- by a function epilogue. */
-int
-register_is_ok_for_epilogue (op, mode)
- rtx op;
- enum machine_mode ATTRIBUTE_UNUSED mode;
-{
- /* The save/restore routines can only cope with registers 2, and 20 - 31 */
- return (GET_CODE (op) == REG)
- && (((REGNO (op) >= 20) && REGNO (op) <= 31)
- || REGNO (op) == 2);
-}
-
-/* Return non-zero if the given RTX is suitable for collapsing into
- jump to a function epilogue. */
-int
-pattern_is_ok_for_epilogue (op, mode)
- rtx op;
- enum machine_mode ATTRIBUTE_UNUSED mode;
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then the function epilogue
- is not suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are performing a
- function epilogue and that we are popping at least one register. We must
- now check the remaining entries in the vector to make sure that they are
- also register pops. There is no good reason why there should ever be
- anything else in this vector, but being paranoid always helps...
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
- (mem:SI (plus:SI (reg:SI 3) (match_operand:SI n "immediate_operand" "i"))))
- */
-
- for (i = 3; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if (GET_CODE (dest) != REG
- || GET_MODE (dest) != SImode
- || ! register_is_ok_for_epilogue (dest, SImode)
- || GET_CODE (src) != MEM
- || GET_MODE (src) != SImode)
- return 0;
-
- plus = XEXP (src, 0);
-
- if (GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
- }
-
- return 1;
-}
-
-/* Construct a JR instruction to a routine that will perform the equivalent of
- the RTL passed in as an argument. This RTL is a function epilogue that
- pops registers off the stack and possibly releases some extra stack space
- as well. The code has already verified that the RTL matches these
- requirements. */
-char *
-construct_restore_jr (op)
- rtx op;
-{
- int count = XVECLEN (op, 0);
- int stack_bytes;
- unsigned long int mask;
- unsigned long int first;
- unsigned long int last;
- int i;
- static char buff [100]; /* XXX */
-
- if (count <= 2)
- {
- error ("Bogus JR construction: %d\n", count);
- return NULL;
- }
-
- /* Work out how many bytes to pop off the stack before retrieving
- registers. */
- if (GET_CODE (XVECEXP (op, 0, 1)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)
- abort ();
-
- stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
-
- /* Each pop will remove 4 bytes from the stack... */
- stack_bytes -= (count - 2) * 4;
-
- /* 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);
- return NULL;
- }
-
- /* Now compute the bit mask of registers to push. */
- mask = 0;
- for (i = 2; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_DEST (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))
- abort ();
-
- mask |= 1 << REGNO (SET_DEST (vector_element));
- }
-
- /* Scan for the first register to pop. */
- for (first = 0; first < 32; first++)
- {
- if (mask & (1 << first))
- break;
- }
-
- if (first >= 32)
- abort ();
-
- /* Discover the last register to pop. */
- if (mask & (1 << LINK_POINTER_REGNUM))
- {
- if (stack_bytes != 16)
- abort ();
-
- last = LINK_POINTER_REGNUM;
- }
- else
- {
- if (stack_bytes != 0)
- abort ();
-
- if ((mask & (1 << 29)) == 0)
- abort ();
-
- last = 29;
- }
-
- /* 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
- {
- 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;
-}
-
-
-/* Return non-zero if the given RTX is suitable for collapsing into
- a jump to a function prologue. */
-int
-pattern_is_ok_for_prologue (op, mode)
- rtx op;
- enum machine_mode ATTRIBUTE_UNUSED mode;
-{
- int count = XVECLEN (op, 0);
- int i;
- rtx vector_element;
-
- /* If there are no registers to save then the function prologue
- is not suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are adjusting the
- stack and pushing at least one register. We must now check that the
- remaining entries in the vector to make sure that they are also register
- pushes, except for the last entry which should be a CLOBBER of r10.
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI 2 "immediate_operand" "i")))
- (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
-
- */
-
- for (i = 2; i < count - 1; i++)
- {
- rtx dest;
- rtx src;
- rtx plus;
-
- vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if (GET_CODE (dest) != MEM
- || GET_MODE (dest) != SImode
- || GET_CODE (src) != REG
- || GET_MODE (src) != SImode
- || ! register_is_ok_for_epilogue (src, SImode))
- return 0;
-
- plus = XEXP (dest, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
-
- /* If the register is being pushed somewhere other than the stack
- 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)))
- {
- return 0;
- }
- }
-
- /* Make sure that the last entry in the vector is a clobber. */
- vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != CLOBBER
- || GET_CODE (XEXP (vector_element, 0)) != REG
- || REGNO (XEXP (vector_element, 0)) != 10)
- return 0;
-
- return 1;
-}
-
-/* Construct a JARL instruction to a routine that will perform the equivalent
- of the RTL passed as a parameter. This RTL is a function prologue that
- saves some of the registers r20 - r31 onto the stack, and possibly acquires
- some stack space as well. The code has already verified that the RTL
- matches these requirements. */
-char *
-construct_save_jarl (op)
- rtx op;
-{
- int count = XVECLEN (op, 0);
- int stack_bytes;
- unsigned long int mask;
- unsigned long int first;
- unsigned long int last;
- int i;
- static char buff [100]; /* XXX */
-
- if (count <= 2)
- {
- error ("Bogus JARL construction: %d\n", count);
- return NULL;
- }
-
- /* Paranoia. */
- if (GET_CODE (XVECEXP (op, 0, 0)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) != REG)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT)
- abort ();
-
- /* Work out how many bytes to push onto the stack after storing the
- registers. */
- stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
-
- /* Each push will put 4 bytes from the stack... */
- stack_bytes += (count - 2) * 4;
-
- /* 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);
- return NULL;
- }
-
- /* Now compute the bit mask of registers to push. */
- mask = 0;
- for (i = 1; i < count - 1; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_SRC (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode))
- abort ();
-
- mask |= 1 << REGNO (SET_SRC (vector_element));
- }
-
- /* Scan for the first register to push. */
- for (first = 0; first < 32; first++)
- {
- if (mask & (1 << first))
- break;
- }
-
- if (first >= 32)
- abort ();
-
- /* Discover the last register to push. */
- if (mask & (1 << LINK_POINTER_REGNUM))
- {
- if (stack_bytes != -16)
- abort ();
-
- last = LINK_POINTER_REGNUM;
- }
- else
- {
- if (stack_bytes != 0)
- abort ();
- if ((mask & (1 << 29)) == 0)
- abort ();
-
- last = 29;
- }
-
- /* 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
- {
- 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;
- 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;
- char * name;
- int size;
- int align;
-{
- if (decl == NULL_TREE)
- {
- fprintf (file, "\t%s\t", COMMON_ASM_OP);
- }
- else
- {
- switch (v850_get_data_area (decl))
- {
- case DATA_AREA_ZDA:
- fprintf (file, "\t%s\t", ZCOMMON_ASM_OP);
- break;
-
- case DATA_AREA_SDA:
- fprintf (file, "\t%s\t", SCOMMON_ASM_OP);
- break;
-
- case DATA_AREA_TDA:
- fprintf (file, "\t%s\t", TCOMMON_ASM_OP);
- break;
-
- default:
- fprintf (file, "\t%s\t", 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;
- char * name;
- int size;
- int align;
-{
- fprintf (file, "\t%s\t", LOCAL_ASM_OP);
- assemble_name (file, name);
- fprintf (file, "\n");
-
- ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
-}
-
-/* The following code is for handling pragmas supported by the
- v850 compiler produced by Green Hills Software. This is at
- the specific request of a customer. */
-
-/* Track the current data area set by the data area pragma (which
- can be nested). Tested by check_default_data_area. */
-
-typedef struct data_area_stack_element
-{
- struct data_area_stack_element * prev;
- v850_data_area data_area; /* current default data area. */
-} data_area_stack_element;
-
-static data_area_stack_element * data_area_stack = NULL;
-
-/* Names of the various data areas used on the v850. */
-static tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
-static tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
-
-/* Push a data area onto the stack. */
-static int
-push_data_area (data_area)
- v850_data_area data_area;
-{
- data_area_stack_element * elem;
-
- elem = (data_area_stack_element *) xmalloc (sizeof (* elem));
-
- if (elem == NULL)
- return 0;
-
- elem->prev = data_area_stack;
- elem->data_area = data_area;
-
- data_area_stack = elem;
-
- return 1;
-}
-
-/* Remove a data area from the stack. */
-static int
-pop_data_area (data_area)
- v850_data_area data_area;
-{
- if (data_area_stack == NULL)
- warning ("#pragma GHS endXXXX found without previous startXXX");
- else if (data_area != data_area_stack->data_area)
- warning ("#pragma GHS endXXX does not match previous startXXX");
- else
- {
- data_area_stack_element * elem;
-
- elem = data_area_stack;
- data_area_stack = data_area_stack->prev;
-
- free (elem);
-
- return 1;
- }
-
- return 0;
-}
-
-/* Set the machine specific 'interrupt' attribute on the current function. */
-static int
-mark_current_function_as_interrupt ()
-{
- tree name;
-
- if (current_function_decl == NULL_TREE)
- {
- warning ("Cannot set interrupt attribute: no current function");
- return 0;
- }
-
- name = get_identifier ("interrupt");
-
- if (name == NULL_TREE || TREE_CODE (name) != IDENTIFIER_NODE)
- {
- warning ("Cannot set interrupt attribute: no such identifier");
- return 0;
- }
-
- return valid_machine_attribute
- (name, NULL_TREE, current_function_decl, NULL_TREE);
-}
-
-/* Parse STRING as part of a GHS pragma.
- Returns 0 if the pragma has been parsed and there was a problem,
- non-zero in all other cases. */
-static int
-parse_ghs_pragma_token (string)
- char * string;
-{
- static enum v850_pragma_state state = V850_PS_START;
- static enum v850_pragma_type type = V850_PT_UNKNOWN;
- static v850_data_area data_area = DATA_AREA_NORMAL;
- static char * data_area_name;
- static enum GHS_section_kind GHS_section_kind = GHS_SECTION_KIND_DEFAULT;
-
- /* If the string is NULL then we have reached the end of the
- #pragma construct. Make sure that we are in an end state, and
- then implement the pragma's directive. */
- if (string == NULL)
- {
- int ret_val = 1;
-
- if (state != V850_PS_SHOULD_BE_DONE
- && state != V850_PS_MAYBE_COMMA
- && state != V850_PS_MAYBE_SECTION_NAME)
- {
- if (state != V850_PS_BAD)
- warning ("Incomplete #pragma ghs");
-
- ret_val = 0;
- }
- else switch (type)
- {
- case V850_PT_UNKNOWN:
- warning ("Nothing follows #pragma ghs");
- ret_val = 0;
- break;
-
- case V850_PT_INTERRUPT:
- ret_val = mark_current_function_as_interrupt ();
- break;
-
- case V850_PT_SECTION:
- /* If a section kind has not been specified, then reset
- all section names back to their defaults. */
- if (GHS_section_kind == GHS_SECTION_KIND_DEFAULT)
- {
- int i;
-
- for (i = COUNT_OF_GHS_SECTION_KINDS; i--;)
- GHS_current_section_names [i] = NULL;
- }
- /* If a section has been specified, then this will be handled
- by check_default_section_name (). */
- break;
-
- case V850_PT_START_SECTION:
- ret_val = push_data_area (data_area);
- break;
-
- case V850_PT_END_SECTION:
- ret_val = pop_data_area (data_area);
- break;
- }
-
- state = V850_PS_START;
- type = V850_PT_UNKNOWN;
-
- return ret_val;
- }
-
- switch (state)
- {
- case V850_PS_START:
- data_area = DATA_AREA_NORMAL;
- data_area_name = NULL;
-
- if (streq (string, "interrupt"))
- {
- type = V850_PT_INTERRUPT;
- state = V850_PS_SHOULD_BE_DONE;
- }
- else if (streq (string, "section"))
- {
- type = V850_PT_SECTION;
- state = V850_PS_MAYBE_SECTION_NAME;
- GHS_section_kind = GHS_SECTION_KIND_DEFAULT;
- }
- else if (streq (string, "starttda"))
- {
- type = V850_PT_START_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_TDA;
- }
- else if (streq (string, "endtda"))
- {
- type = V850_PT_END_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_TDA;
- }
- else if (streq (string, "startsda"))
- {
- type = V850_PT_START_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_SDA;
- }
- else if (streq (string, "endsda"))
- {
- type = V850_PT_END_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_SDA;
- }
- else if (streq (string, "startzda"))
- {
- type = V850_PT_START_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_ZDA;
- }
- else if (streq (string, "endzda"))
- {
- type = V850_PT_END_SECTION;
- state = V850_PS_SHOULD_BE_DONE;
- data_area = DATA_AREA_ZDA;
- }
- else
- {
- warning ("Unrecognised GHS pragma: '%s'\n", string);
- state = V850_PS_BAD;
- }
- break;
-
- case V850_PS_SHOULD_BE_DONE:
- warning ("Extra text after valid #pragma: '%s'", string);
- state = V850_PS_BAD;
- break;
-
- case V850_PS_BAD:
- /* Ignore tokens in a pragma that has been diagnosed as being corrupt. */
- break;
-
- case V850_PS_MAYBE_SECTION_NAME:
- state = V850_PS_EXPECTING_EQUALS;
-
- if (streq (string, "data")) GHS_section_kind = GHS_SECTION_KIND_DATA;
- else if (streq (string, "text")) GHS_section_kind = GHS_SECTION_KIND_TEXT;
- else if (streq (string, "rodata")) GHS_section_kind = GHS_SECTION_KIND_RODATA;
- else if (streq (string, "const")) GHS_section_kind = GHS_SECTION_KIND_RODATA;
- else if (streq (string, "rosdata")) GHS_section_kind = GHS_SECTION_KIND_ROSDATA;
- else if (streq (string, "rozdata")) GHS_section_kind = GHS_SECTION_KIND_ROZDATA;
- else if (streq (string, "sdata")) GHS_section_kind = GHS_SECTION_KIND_SDATA;
- else if (streq (string, "tdata")) GHS_section_kind = GHS_SECTION_KIND_TDATA;
- else if (streq (string, "zdata")) GHS_section_kind = GHS_SECTION_KIND_ZDATA;
- /* According to GHS beta documentation, the following should not be allowed! */
- else if (streq (string, "bss")) GHS_section_kind = GHS_SECTION_KIND_BSS;
- else if (streq (string, "zbss")) GHS_section_kind = GHS_SECTION_KIND_ZDATA;
- else
- {
- warning ("Unrecognised section name '%s' in GHS section pragma",
- string);
- state = V850_PS_BAD;
- }
- break;
-
- case V850_PS_EXPECTING_EQUALS:
- if (streq (string, "="))
- state = V850_PS_EXPECTING_SECTION_ALIAS;
- else
- {
- warning ("Missing '=' in GHS section pragma");
- state = V850_PS_BAD;
- }
- break;
-
- case V850_PS_EXPECTING_SECTION_ALIAS:
- if (streq (string, "default"))
- GHS_current_section_names [GHS_section_kind] = NULL;
- else
- GHS_current_section_names [GHS_section_kind] =
- build_string (strlen (string) + 1, string);
-
- state = V850_PS_MAYBE_COMMA;
- break;
-
- case V850_PS_MAYBE_COMMA:
- if (streq (string, ","))
- state = V850_PS_MAYBE_SECTION_NAME;
- else
- {
- warning
- ("Malformed GHS section pragma: found '%s' instead of a comma",
- string);
- state = V850_PS_BAD;
- }
- break;
- }
-
- return 1;
-}
-
-/* Handle the parsing of an entire GHS pragma. */
-int
-v850_handle_pragma (p_getc, p_ungetc, name)
- int (* p_getc) PROTO ((void));
- void (* p_ungetc) PROTO ((int));
- char * name;
-{
- /* Parse characters in the input stream until:
-
- * end of line
- * end of file
- * a complete GHS pragma has been parsed
- * a corrupted GHS pragma has been parsed
- * an unknown pragma is encountered.
-
- If an unknown pragma is encountered, we must return with
- the input stream in the same state as upon entry to this function.
-
- The first token in the input stream has already been parsed
- for us, and is passed as 'name'. */
-
- if (! streq (name, "ghs"))
- return 0;
-
- /* We now know that we are parsing a GHS pragma, so we do
- not need to preserve the original input stream state. */
- for (;;)
- {
- static char buffer [128];
- int c;
- char * buff;
-
- /* Skip white space. */
- do
- c = p_getc ();
- while (c == ' ' || c == '\t');
-
- p_ungetc (c);
-
- if (c == '\n' || c == EOF || c == '\r')
- return parse_ghs_pragma_token (NULL);
-
- /* Read next word. We have to do the parsing ourselves, rather
- than calling yylex() because we can be built with front ends
- that do not provide such functions. */
- buff = buffer;
- * buff ++ = (c = p_getc ());
-
- switch (c)
- {
- case ',':
- case '=':
- * buff ++ = (c = p_getc ());
- break;
-
- case '"':
- /* Skip opening double parenthesis. */
- -- buff;
-
- /* Read string. */
- do
- * buff ++ = (c = p_getc ());
- while (c != EOF && isascii (c)
- && (isalnum (c) || c == '_' || c == '.' || c == ' ')
- && (buff < buffer + 126));
-
- if (c != '"')
- warning ("Missing trailing \" in #pragma ghs");
- else
- c = p_getc ();
- break;
-
- default:
- while (c != EOF && isascii (c)
- && (isalnum (c) || c == '_' || c == '.')
- && (buff < buffer + 126))
- * buff ++ = (c = p_getc ());
- break;
- }
-
- p_ungetc (c);
-
- /* If nothing was read then terminate the parsing. */
- if (buff == buffer + 1)
- return parse_ghs_pragma_token (NULL);
-
- /* Parse and continue. */
- * -- buff = 0;
-
- parse_ghs_pragma_token (buffer);
- }
-}
-
-/* Add data area to the given declaration if a ghs data area pragma is
- currently in effect (#pragma ghs startXXX/endXXX). */
-void
-v850_set_default_decl_attr (decl)
- tree decl;
-{
- 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;
- }
- }
-}
-
-/* CYGNUS LOCAL v850e */
-/* Return non-zero if the given RTX is suitable for collapsing into a
- DISPOSE instruction. */
-int
-pattern_is_ok_for_dispose (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then the dispose instruction is not
- suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are performing a
- function epilogue and that we are popping at least one register. We must
- now check the remaining entries in the vector to make sure that they are
- also register pops. There is no good reason why there should ever be
- anything else in this vector, but being paranoid always helps...
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
- (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI n "immediate_operand" "i"))))
- */
-
- for (i = 3; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if ( GET_CODE (dest) != REG
- || GET_MODE (dest) != SImode
- || ! register_is_ok_for_epilogue (dest, SImode)
- || GET_CODE (src) != MEM
- || GET_MODE (src) != SImode)
- return 0;
-
- plus = XEXP (src, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
- }
-
- return 1;
-}
-
-/* Construct a DISPOSE instruction that is the equivalent of
- the given RTX. We have already verified that this should
- be possible. */
-char *
-construct_dispose_instruction (op)
- rtx op;
-{
- int count = XVECLEN (op, 0);
- int stack_bytes;
- unsigned long int mask;
- int i;
- static char buff[ 100 ]; /* XXX */
- int use_callt = 0;
-
- if (count <= 2)
- {
- error ("Bogus DISPOSE construction: %d\n", count);
- return NULL;
- }
-
- /* Work out how many bytes to pop off the stack before retrieving
- registers. */
- if (GET_CODE (XVECEXP (op, 0, 1)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)
- abort ();
-
- stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
-
- /* Each pop will remove 4 bytes from the stack... */
-
- stack_bytes -= (count - 2) * 4;
-
- /* Make sure that the amount we are popping will fit into the DISPOSE
- instruction. */
- if (stack_bytes > 128)
- {
- error ("Too much stack space to dispose of: %d", stack_bytes);
- return NULL;
- }
-
- /* Now compute the bit mask of registers to push. */
- mask = 0;
-
- for (i = 2; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_DEST (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))
- abort ();
-
- if (REGNO (SET_DEST (vector_element)) == 2)
- use_callt = 1;
- else
- mask |= 1 << REGNO (SET_DEST (vector_element));
- }
-
- if (! TARGET_DISABLE_CALLT
- && (use_callt || stack_bytes == 0 || stack_bytes == 16))
- {
- if (use_callt)
- {
- sprintf (buff, "callt ctoff(__callt_return_r2_r%d)", (mask & (1 << 31)) ? 31 : 29);
- return buff;
- }
- else
- {
- for (i = 20; i < 32; i++)
- {
- if (mask & (1 << i))
- break;
- }
-
- if (i == 31)
- {
- sprintf (buff, "callt ctoff(__callt_return_r31c)");
- }
- else
- {
- sprintf (buff, "callt ctoff(__callt_return_r%d_r%d%s)",
- i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
- }
- }
- }
- else
- {
- static char regs [100]; /* XXX */
- int done_one;
-
- /* Generate the DISPOSE instruction. Note we could just issue the
- bit mask as a number as the assembler can cope with this, but for
- the sake of our readers we turn it into a textual description. */
-
- regs[0] = 0;
- done_one = 0;
-
- for (i = 20; i < 32; i++)
- {
- if (mask & (1 << i))
- {
- int first;
-
- if (done_one)
- strcat (regs, ", ");
- else
- done_one = 1;
-
- first = i;
- strcat (regs, reg_names[ first ]);
-
- for (i++; i < 32; i++)
- if ((mask & (1 << i)) == 0)
- break;
-
- if (i > first + 1)
- {
- strcat (regs, " - ");
- strcat (regs, reg_names[ i - 1 ] );
- }
- }
- }
-
- sprintf (buff, "dispose %d {%s}, r31", stack_bytes / 4, regs);
- }
-
- return buff;
-}
-
-/* Return non-zero if the given RTX is suitable for collapsing into a PREPARE
- instruction. */
-int
-pattern_is_ok_for_prepare (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then the prepare instruction
- is not suitable. */
- if (count <= 1)
- return 0;
-
- /* The pattern matching has already established that we are adjusting the
- stack and pushing at least one register. We must now check that the
- remaining entries in the vector to make sure that they are also register
- pushes.
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI 2 "immediate_operand" "i")))
- (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
-
- */
-
- for (i = 2; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if ( GET_CODE (dest) != MEM
- || GET_MODE (dest) != SImode
- || GET_CODE (src) != REG
- || GET_MODE (src) != SImode
- || ! register_is_ok_for_epilogue (src, SImode)
- )
- return 0;
-
- plus = XEXP (dest, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- 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. */
- if (INTVAL (XEXP (plus, 1))
- <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
- {
- return 0;
- }
- }
-
- return 1;
-}
-
-/* Construct a PREPARE instruction that is the equivalent of
- the given RTL. We have already verified that this should
- be possible. */
-char *
-construct_prepare_instruction (op)
- rtx op;
-{
- int count = XVECLEN (op, 0);
- int stack_bytes;
- unsigned long int mask;
- int i;
- static char buff[ 100 ]; /* XXX */
- int use_callt = 0;
-
- if (count <= 1)
- {
- error ("Bogus PREPEARE construction: %d\n", count);
- return NULL;
- }
-
- /* Work out how many bytes to push onto the stack after storing the
- registers. */
- if (GET_CODE (XVECEXP (op, 0, 0)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT)
- abort ();
-
- stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
-
- /* Each push will put 4 bytes from the stack... */
- stack_bytes += (count - 1) * 4;
-
- /* Make sure that the amount we are popping will fit into the DISPOSE
- instruction. */
- if (stack_bytes < -128)
- {
- error ("Too much stack space to prepare: %d", stack_bytes);
- return NULL;
- }
-
- /* Now compute the bit mask of registers to push. */
- mask = 0;
- for (i = 1; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_SRC (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode))
- abort ();
-
- if (REGNO (SET_SRC (vector_element)) == 2)
- use_callt = 1;
- else
- mask |= 1 << REGNO (SET_SRC (vector_element));
- }
-
- if ((! TARGET_DISABLE_CALLT)
- && (use_callt || stack_bytes == 0 || stack_bytes == -16))
- {
- if (use_callt)
- {
- sprintf (buff, "callt ctoff(__callt_save_r2_r%d)", (mask & (1 << 31)) ? 31 : 29 );
- return buff;
- }
-
- for (i = 20; i < 32; i++)
- {
- if (mask & (1 << i))
- break;
- }
-
- if (i == 31)
- {
- sprintf (buff, "callt ctoff(__callt_save_r31c)");
- }
- else
- {
- sprintf (buff, "callt ctoff(__callt_save_r%d_r%d%s)",
- i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
- }
- }
- else
- {
- static char regs [100]; /* XXX */
- int done_one;
-
-
- /* Generate the PREPARE instruction. Note we could just issue the
- bit mask as a number as the assembler can cope with this, but for
- the sake of our readers we turn it into a textual description. */
-
- regs[0] = 0;
- done_one = 0;
-
- for (i = 20; i < 32; i++)
- {
- if (mask & (1 << i))
- {
- int first;
-
- if (done_one)
- strcat (regs, ", ");
- else
- done_one = 1;
-
- first = i;
- strcat (regs, reg_names[ first ]);
-
- for (i++; i < 32; i++)
- if ((mask & (1 << i)) == 0)
- break;
-
- if (i > first + 1)
- {
- strcat (regs, " - ");
- strcat (regs, reg_names[ i - 1 ] );
- }
- }
- }
-
- sprintf (buff, "prepare {%s}, %d", regs, (- stack_bytes) / 4);
- }
-
- return buff;
-}
-
-/* END CYGNUS LOCAL */