#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
#include "output.h"
#include "function.h"
#include "expr.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1];
enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
enum reg_class reg_class_from_letter[256];
int target_cpu;
int current_section_is_text;
static rtx cmp_operand0, cmp_operand1;
static char cmp_modech;
#if 0
static rtx frame_argblock;
static int frame_argblock_size;
static rtx convert_arg_pushes ();
#endif
static void expand_movstr_call PARAMS ((rtx *));
static void convex_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void convex_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static int convex_adjust_cost PARAMS ((rtx, rtx, rtx, int));
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP "\tds.b\t"
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\tds.h\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\tds.w\t"
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE convex_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE convex_output_function_epilogue
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST convex_adjust_cost
struct gcc_target targetm = TARGET_INITIALIZER;
static void
convex_output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
size = ((size) + 7) & -8;
if (size)
{
fprintf (file, "\tsub.w #");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
fprintf (file, ",sp\n");
}
}
static void
convex_output_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
fprintf (file, "\tds.h 0\n");
}
static int
convex_adjust_cost (insn, link, dep, cost)
rtx insn;
rtx link;
rtx dep;
int cost;
{
if (REG_NOTE_KIND (link) != 0)
cost = 0;
else if (TARGET_C38
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (PATTERN (dep)) == SET)
{
enum attr_type insn_type = get_attr_type (insn);
enum attr_type dep_type = get_attr_type (dep);
if (insn_type == TYPE_MLDW || insn_type == TYPE_MLDL
|| (insn_type == TYPE_MST
&& reg_mentioned_p (SET_DEST (PATTERN (dep)),
SET_SRC (PATTERN (insn)))))
cost += 1;
if (dep_type == TYPE_ALU
&& insn_type != TYPE_ALU
&& ! (insn_type == TYPE_MST
&& SET_DEST (PATTERN (dep)) == SET_SRC (PATTERN (insn))))
cost += 1;
}
return cost;
}
void
init_convex ()
{
int regno;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (A_REGNO_P (regno))
{
regno_ok_for_index_p[regno] = 1;
regno_reg_class[regno] = INDEX_REGS;
}
else
{
regno_ok_for_index_p[regno] = 0;
regno_reg_class[regno] = S_REGS;
}
regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0;
regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS;
regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1;
regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1;
regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0;
regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0;
regno_ok_for_index_p[-1] = 0;
reg_class_from_letter['a'] = A_REGS;
reg_class_from_letter['A'] = INDEX_REGS;
reg_class_from_letter['d'] = S_REGS;
psw_disable_float ();
}
void
psw_disable_float ()
{
#if __convex__ && __GNUC__
register int *p;
asm ("mov fp,%0" : "=a" (p));
while (p)
{
p[1] &= ~0x1000c400;
p = (int *) p[2];
}
#endif
}
const char *
output_cmp (operand0, operand1, modech)
rtx operand0, operand1;
int modech;
{
cmp_operand0 = operand0;
cmp_operand1 = operand1;
cmp_modech = modech;
return "";
}
const char *
output_condjump (label, cond, jbr_sense)
rtx label;
const char *cond;
int jbr_sense;
{
rtx operands[3];
char cmp_op[4];
char buf[80];
char jbr_regch;
strcpy (cmp_op, cond);
if (cmp_modech == 'B' || cmp_modech == 'L')
{
cmp_modech = cmp_modech - 'A' + 'a';
strcpy (cmp_op, "neg");
}
else if (cmp_modech == 'W' || cmp_modech == 'H')
{
if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx)
jbr_sense ^= 't' ^ 'f';
else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx)
;
else
cmp_modech = cmp_modech - 'A' + 'a';
}
if (! REG_P (cmp_operand1))
{
operands[0] = cmp_operand1;
operands[1] = cmp_operand0;
if (cmp_op[0] == 'l')
{
cmp_op[1] ^= 'e' ^ 't';
jbr_sense ^= 't' ^ 'f';
}
}
else
{
operands[0] = cmp_operand0;
operands[1] = cmp_operand1;
}
operands[2] = label;
if (S_REG_P (operands[1]))
jbr_regch = 's';
else if (A_REG_P (operands[1]))
jbr_regch = 'a';
else
abort ();
if (cmp_modech == 'W' || cmp_modech == 'H')
sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
else
sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2",
cmp_op, cmp_modech, jbr_regch, jbr_sense);
output_asm_insn (buf, operands);
return "";
}
int
nonmemory_cmpsf_operand (op, mode)
rtx op;
enum machine_mode mode;
{
#if _IEEE_FLOAT_
if (op == CONST0_RTX (SFmode))
return 0;
#endif
return nonmemory_operand (op, mode);
}
rtx
simplify_for_convex (x)
rtx x;
{
switch (GET_CODE (x))
{
case MINUS:
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < 0)
{
PUT_CODE (x, PLUS);
XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
}
break;
case CONST:
return simplify_for_convex (XEXP (x, 0));
default:
break;
}
return x;
}
int
const_double_high_int (x)
rtx x;
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return CONST_DOUBLE_LOW (x);
else
return CONST_DOUBLE_HIGH (x);
}
int
const_double_low_int (x)
rtx x;
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return CONST_DOUBLE_HIGH (x);
else
return CONST_DOUBLE_LOW (x);
}
void
expand_movstr (operands)
rtx *operands;
{
rtx dest = operands[0];
rtx src = operands[1];
int align = INTVAL (operands[3]);
int nregs, maxsize;
unsigned len;
enum machine_mode mode;
rtx reg, load, store, prev_store, prev_store_2;
int size;
if (TARGET_C1)
{
nregs = 3, maxsize = 8;
}
else if (TARGET_C2)
{
if (align >= 4)
nregs = 2, maxsize = 8;
else
nregs = 2, maxsize = 4;
}
else if (TARGET_C34)
{
nregs = 3, maxsize = align;
}
else if (TARGET_C38)
{
if (align >= 4)
nregs = 2, maxsize = 8;
else
nregs = 3, maxsize = 8;
}
else
abort ();
if (GET_CODE (operands[2]) != CONST_INT
|| (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
{
expand_movstr_call (operands);
return;
}
reg = 0;
prev_store = prev_store_2 = 0;
while (len > 0)
{
if (len >= 8 && maxsize >= 8)
mode = DImode;
else if (len >= 4 && maxsize >= 4)
mode = SImode;
else if (len >= 2 && maxsize >= 2)
mode = HImode;
else
mode = QImode;
if (! reg || GET_MODE (reg) != mode)
reg = gen_reg_rtx (mode);
if (GET_MODE (src) != mode)
{
src = adjust_address (src, mode, 0);
dest = adjust_address (dest, mode, 0);
}
load = gen_rtx_SET (VOIDmode, reg, src);
store = gen_rtx_SET (VOIDmode, dest, reg);
emit_insn (load);
if (prev_store)
{
reg = SET_SRC (prev_store);
emit_insn (prev_store);
}
else
reg = 0;
if (nregs == 2)
prev_store = store;
else
prev_store = prev_store_2, prev_store_2 = store;
size = GET_MODE_SIZE (mode);
src = adjust_address (src, mode, size);
dest = adjust_address (dest, mode, size);
len -= size;
}
if (prev_store)
emit_insn (prev_store);
if (prev_store_2)
emit_insn (prev_store_2);
}
static void
expand_movstr_call (operands)
rtx *operands;
{
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
VOIDmode, 3,
XEXP (operands[0], 0), Pmode,
XEXP (operands[1], 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype), operands[2],
TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
}
#if _IEEE_FLOAT_
#define MAX_FLOAT 3.4028234663852886e+38
#define MIN_FLOAT 1.1754943508222875e-38
#else
#define MAX_FLOAT 1.7014117331926443e+38
#define MIN_FLOAT 2.9387358770557188e-39
#endif
int
check_float_value (mode, dp, overflow)
enum machine_mode mode;
REAL_VALUE_TYPE *dp;
int overflow;
{
REAL_VALUE_TYPE d = *dp;
if (overflow)
{
*dp = MAX_FLOAT;
return 1;
}
if (mode == SFmode)
{
if (d > MAX_FLOAT)
{
*dp = MAX_FLOAT;
return 1;
}
else if (d < -MAX_FLOAT)
{
*dp = -MAX_FLOAT;
return 1;
}
else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
{
*dp = 0.0;
return 1;
}
}
return 0;
}
void
asm_declare_function_name (file, name, decl)
FILE *file;
const char *name;
tree decl;
{
int nargs = list_length (DECL_ARGUMENTS (decl));
const char *p;
char c;
static char vers[4];
int i;
p = version_string;
for (i = 0; i < 3; ) {
c = *p;
if (ISDIGIT (c))
vers[i++] = c;
if (c == 0 || c == ' ')
vers[i++] = '0';
else
p++;
}
fprintf (file, "\tds.b \"g%s\"\n", vers);
if (nargs < 100)
fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs);
else
fprintf (file, "\tds.b \"+00\\0\"\n");
ASM_OUTPUT_LABEL (file, name);
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
long u[2];
REAL_VALUE_TYPE d;
switch (GET_CODE (x))
{
case REG:
fprintf (file, "%s", reg_names[REGNO (x)]);
break;
case MEM:
output_address (XEXP (x, 0));
break;
case CONST_DOUBLE:
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
switch (GET_MODE (x)) {
case DFmode:
#if 0
REAL_VALUE_TO_TARGET_DOUBLE (d, u);
#else
{
union { double d; int i[2]; } t;
t.d = d;
u[0] = t.i[0];
u[1] = t.i[1];
}
#endif
if (code == 'u')
fprintf (file, "#%#lx", u[0]);
else if (code == 'v')
fprintf (file, "#%#lx", u[1]);
else
outfloat (file, d, "%.17e", "#", "");
break;
case SFmode:
outfloat (file, d, "%.9e", "#", "");
break;
default:
if (code == 'u')
{
fprintf (file, "#");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_HIGH (x));
}
else
{
fprintf (file, "#");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
}
}
break;
default:
if (code == 'z')
{
if (GET_CODE (x) != CONST_INT)
abort ();
fprintf (file, "#%d", 1 << INTVAL (x));
}
else
{
putc ('#', file);
output_addr_const (file, x);
}
}
}
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
rtx index = 0;
rtx offset = 0;
if (GET_CODE (addr) == MEM)
{
fprintf (file, "@");
addr = XEXP (addr, 0);
}
switch (GET_CODE (addr))
{
case REG:
index = addr;
break;
case PLUS:
index = XEXP (addr, 0);
if (REG_P (index))
offset = XEXP (addr, 1);
else
{
offset = XEXP (addr, 0);
index = XEXP (addr, 1);
if (! REG_P (index))
abort ();
}
break;
default:
offset = addr;
break;
}
if (offset)
output_addr_const (file, offset);
if (index)
fprintf (file, "(%s)", reg_names[REGNO (index)]);
}
void
outfloat (file, value, fmt, pfx, sfx)
FILE *file;
REAL_VALUE_TYPE value;
const char *fmt, *pfx, *sfx;
{
char buf[64];
fputs (pfx, file);
REAL_VALUE_TO_DECIMAL (value, fmt, buf);
fputs (buf, file);
fputs (sfx, file);
}
void
replace_arg_pushes ()
{
}
const char *
output_call (insn, operands)
rtx insn ATTRIBUTE_UNUSED, *operands;
{
if (operands[4] == stack_pointer_rtx)
output_asm_insn ("mov sp,ap", operands);
else
abort ();
if (TARGET_ARGCOUNT)
output_asm_insn ("pshea %a2", operands);
output_asm_insn ("calls %0", operands);
output_asm_insn ("ld.w 12(fp),ap", operands);
if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx)
output_asm_insn ("add.w %3,sp", operands);
return "";
}
void
emit_ap_optimizations ()
{
}