#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 "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "expr.h"
#include "function.h"
#include "toplev.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
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 *));
struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
{
{ "tda", (char *)0, 0, 256 },
{ "sda", (char *)0, 0, 65536 },
{ "zda", (char *)0, 0, 32768 },
};
tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
data_area_stack_element * data_area_stack = NULL;
static int v850_interrupt_cache_p = FALSE;
static int v850_interrupt_p = FALSE;
#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;
void
override_options ()
{
int i;
extern int atoi PARAMS ((const char *));
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);
}
}
}
if ((target_flags & MASK_US_MASK_SET) == 0)
{
target_flags |= MASK_US_MASK_SET;
target_flags &= ~MASK_US_BIT_SET;
}
}
void
asm_file_start (file)
FILE *file;
{
output_file_directive (file, main_input_filename);
}
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 (size < 1)
return 0;
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;
}
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;
}
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];
*p_low = t[0];
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);
}
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;
}
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
HOST_WIDE_INT high, low;
switch (code)
{
case 'c':
if (GET_CODE (x) == SYMBOL_REF)
{
output_addr_const(file, x);
break;
}
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':
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':
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))
{
const 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))
{
const 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':
switch (GET_CODE (x))
{
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 (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
fputs ("s", file);
break;
}
case 'T':
{
if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), TRUE))
fputs ("s", file);
break;
}
case 'W':
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 '.':
fputs (reg_names[0], file);
break;
case 'z':
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[subreg_regno (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;
}
}
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)
{
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)
{
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)))
{
const char *name = XSTR (addr, 0);
const char *off_name;
const 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))
{
const char *name = XSTR (XEXP (XEXP (addr, 0), 0), 0);
const char *off_name;
const 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;
}
}
int
v850_output_addr_const_extra (file, x)
FILE * file;
rtx x;
{
if (GET_CODE (x) != TRUNCATE)
return 0;
x = XEXP (x, 0);
if (GET_CODE (x) == MINUS
&& GET_CODE (XEXP (x, 0)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == CODE_LABEL
&& INSN_DELETED_P (XEXP (XEXP (x, 0), 0)))
return 1;
output_addr_const (file, x);
return 1;
}
const 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))
return "mov %1,%0";
else if (CONST_OK_FOR_K (value))
return "movea lo(%1),%.,%0";
else if (CONST_OK_FOR_L (value))
return "movhi hi(%1),%.,%0";
else if (TARGET_V850E)
return "mov %1,%0";
else
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))
return "mov %F1,%0";
else if (CONST_OK_FOR_K (high))
return "movea lo(%F1),%.,%0";
else if (CONST_OK_FOR_L (high))
return "movhi hi(%F1),%.,%0";
else if (TARGET_V850E)
return "mov %F1,%0";
else
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)
{
if (TARGET_V850E)
return "mov hilo(%1),%0";
else
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 "";
}
const 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";
}
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 = subreg_regno (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";
}
static int
ep_memory_offset (mode, unsignedp)
enum machine_mode mode;
int ATTRIBUTE_UNUSED unsignedp;
{
int max_offset = 0;
switch (mode)
{
case QImode:
if (TARGET_SMALL_SLD)
max_offset = (1 << 4);
else if (TARGET_V850E
&& ( ( unsignedp && ! TARGET_US_BIT_SET)
|| (! unsignedp && TARGET_US_BIT_SET)))
max_offset = (1 << 4);
else
max_offset = (1 << 7);
break;
case HImode:
if (TARGET_SMALL_SLD)
max_offset = (1 << 5);
else if (TARGET_V850E
&& ( ( unsignedp && ! TARGET_US_BIT_SET)
|| (! unsignedp && TARGET_US_BIT_SET)))
max_offset = (1 << 5);
else
max_offset = (1 << 8);
break;
case SImode:
case SFmode:
max_offset = (1 << 8);
break;
default:
break;
}
return max_offset;
}
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;
}
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);
}
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);
}
int
reg_or_int9_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
return CONST_OK_FOR_O (INTVAL (op));
return register_operand (op, mode);
}
int
reg_or_const_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
return TRUE;
return register_operand (op, mode);
}
int
call_address_operand (op, mode)
rtx op;
enum machine_mode ATTRIBUTE_UNUSED mode;
{
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;
{
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;
}
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);
if (pattern)
{
rtx *p_mem;
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);
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;
}
else
p_mem = (rtx *)0;
if (p_mem)
{
rtx addr = XEXP (*p_mem, 0);
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)) == (unsigned) 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)));
}
}
}
}
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);
}
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 (!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))
{
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);
if (pattern)
{
rtx src = SET_SRC (pattern);
rtx dest = SET_DEST (pattern);
rtx mem;
int unsignedp = FALSE;
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 if (GET_CODE (dest) == MEM)
mem = dest;
else if (GET_CODE (src) == MEM)
mem = src;
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;
}
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;
}
}
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)
{
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);
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;
}
}
}
}
}
}
#define INTERRUPT_FIXED_NUM 4
#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)
#define INTERRUPT_REGPARM_NUM 4
#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;
if (current_function_profile && !call_p)
regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
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;
case 0:
case STACK_POINTER_REGNUM:
break;
case 1:
case 4:
case 10:
case EP_REGNUM:
size += 4;
break;
}
}
else
{
for (i = 0; i <= 31; i++)
if (regs_ever_live[i] && ((! call_used_regs[i])
|| i == LINK_POINTER_REGNUM))
break;
if (TARGET_PROLOG_FUNCTION
&& (i == 2 || ((i >= 20) && (i < 30))))
{
if (i == 2)
{
size += 4;
reg_saved |= 1L << i;
i = 20;
}
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;
{
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, ®_saved);
if (interrupt_handler)
{
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
emit_insn (gen_callt_save_interrupt ());
else
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;
}
else if (current_function_args_info.anonymous_args)
{
if (TARGET_PROLOG_FUNCTION)
{
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
emit_insn (gen_save_r6_r9_v850e ());
else
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;
}
}
}
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 (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
save_regs[num_save++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
default_stack = 16;
}
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;
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;
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,
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));
}
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);
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 (!save_all)
{
if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
emit_insn (gen_callt_save_all_interrupt ());
else
emit_insn (gen_save_all_interrupt ());
}
else
{
if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
init_stack_alloc = compute_register_save_size (NULL);
else
init_stack_alloc = actual_fsize;
offset = init_stack_alloc - 4;
if (init_stack_alloc)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-init_stack_alloc)));
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;
}
}
}
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 (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, ®_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);
if (interrupt_handler)
{
actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
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);
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 (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
default_stack = 16;
}
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;
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;
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);
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 (!restore_all)
{
if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
init_stack_free = 4 * num_restore;
else
init_stack_free = actual_fsize;
if (actual_fsize > 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);
emit_move_insn (reg, GEN_INT (diff));
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
reg));
}
}
if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
{
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
emit_insn (gen_callt_restore_all_interrupt ());
else
emit_insn (gen_restore_all_interrupt ());
}
else
{
offset = init_stack_free - 4;
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)));
emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
offset -= 4;
}
if (init_stack_free)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (init_stack_free)));
}
if (interrupt_handler)
{
if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
emit_insn (gen_callt_return_interrupt ());
else
emit_jump_insn (gen_return_interrupt ());
}
else if (actual_fsize)
emit_jump_insn (gen_return_internal ());
else
emit_jump_insn (gen_return ());
}
v850_interrupt_cache_p = FALSE;
v850_interrupt_p = FALSE;
}
void
notice_update_cc (body, insn)
rtx body;
rtx insn;
{
switch (get_attr_cc (insn))
{
case CC_NONE:
break;
case CC_NONE_0HIT:
if (cc_status.value1 != 0
&& reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
cc_status.value1 = 0;
break;
case CC_SET_ZN:
CC_STATUS_INIT;
cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
cc_status.value1 = recog_data.operand[0];
break;
case CC_SET_ZNV:
CC_STATUS_INIT;
cc_status.flags |= CC_NO_CARRY;
cc_status.value1 = recog_data.operand[0];
break;
case CC_COMPARE:
CC_STATUS_INIT;
cc_status.value1 = SET_SRC (body);
break;
case CC_CLOBBER:
CC_STATUS_INIT;
break;
}
}
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;
return DATA_AREA_NORMAL;
}
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_ATTRIBUTES (decl) = tree_cons
(name, NULL, DECL_ATTRIBUTES (decl));
}
const struct attribute_spec v850_attribute_table[] =
{
{ "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 }
};
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;
}
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;
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;
}
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 NULL_TREE;
}
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_ATTRIBUTES (func));
if (a != NULL_TREE)
ret = 1;
else
{
a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
ret = a != NULL_TREE;
}
if (reload_completed | reload_in_progress)
v850_interrupt_p = ret;
return ret;
}
static void
v850_encode_data_area (decl)
tree decl;
{
const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
int len = strlen (str);
char * newstr;
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);
}
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);
}
static const char *
v850_strip_name_encoding (str)
const char *str;
{
return str + (ENCODED_NAME_P (str) || *str == '*');
}
int
register_is_ok_for_epilogue (op, mode)
rtx op;
enum machine_mode ATTRIBUTE_UNUSED mode;
{
return ((GET_CODE (op) == REG)
&& (((REGNO (op) >= 20) && REGNO (op) <= 31)));
}
int
pattern_is_ok_for_epilogue (op, mode)
rtx op;
enum machine_mode ATTRIBUTE_UNUSED mode;
{
int count = XVECLEN (op, 0);
int i;
if (count <= 2)
return 0;
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;
}
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];
if (count <= 2)
{
error ("bogus JR construction: %d\n", count);
return NULL;
}
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));
stack_bytes -= (count - 2) * 4;
if (stack_bytes != 0 && stack_bytes != 16)
{
error ("bad amount of stack space removal: %d", stack_bytes);
return NULL;
}
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));
}
for (first = 0; first < 32; first++)
{
if (mask & (1 << first))
break;
}
if (first >= 32)
abort ();
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;
}
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;
}
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 (count <= 2)
return 0;
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 (INTVAL (XEXP (plus, 1))
<= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
{
return 0;
}
}
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;
}
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];
if (count <= 2)
{
error ("bogus JARL construction: %d\n", count);
return NULL;
}
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 ();
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
stack_bytes += (count - 2) * 4;
if (stack_bytes != 0 && stack_bytes != -16)
{
error ("bad amount of stack space removal: %d", stack_bytes);
return NULL;
}
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));
}
for (first = 0; first < 32; first++)
{
if (mask & (1 << first))
break;
}
if (first >= 32)
abort ();
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;
}
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;
void
v850_output_aligned_bss (file, decl, name, size, align)
FILE * file;
tree decl;
const char * name;
int size;
int align;
{
(*targetm.asm_out.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
ASM_OUTPUT_LABEL (file, name);
#endif
ASM_OUTPUT_SKIP (file, size ? size : 1);
}
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);
}
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);
}
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);
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
{
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:
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;
}
}
chosen_section = GHS_current_section_names [(int) kind];
if (chosen_section == NULL)
chosen_section = GHS_default_section_names [(int) kind];
if (chosen_section)
{
DECL_SECTION_NAME (decl) = chosen_section;
}
}
}
int
pattern_is_ok_for_dispose (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int count = XVECLEN (op, 0);
int i;
if (count <= 2)
return 0;
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;
}
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 ];
int use_callt = 0;
if (count <= 2)
{
error ("Bogus DISPOSE construction: %d\n", count);
return NULL;
}
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));
stack_bytes -= (count - 2) * 4;
if (stack_bytes > 128)
{
error ("Too much stack space to dispose of: %d", stack_bytes);
return NULL;
}
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];
int done_one;
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;
}
int
pattern_is_ok_for_prepare (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
int count = XVECLEN (op, 0);
int i;
if (count <= 1)
return 0;
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 (INTVAL (XEXP (plus, 1))
<= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
return 0;
}
return 1;
}
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 ];
int use_callt = 0;
if (count <= 1)
{
error ("Bogus PREPEARE construction: %d\n", count);
return NULL;
}
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));
stack_bytes += (count - 1) * 4;
if (stack_bytes < -128)
{
error ("Too much stack space to prepare: %d", stack_bytes);
return NULL;
}
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];
int done_one;
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;
}
rtx
v850_va_arg (valist, type)
tree valist, type;
{
HOST_WIDE_INT size, rsize;
tree addr, incr;
rtx addr_rtx;
int indirect;
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;
}
rtx
v850_return_addr (count)
int count;
{
if (count != 0)
return const0_rtx;
return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
}
static void
v850_select_section (exp, reloc, align)
tree exp;
int reloc ATTRIBUTE_UNUSED;
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 ();
}