#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "function.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "tree.h"
#include "expr.h"
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
int current_first_parm_offset;
static void encode_pdp11_f (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_pdp11_f (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void encode_pdp11_d (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_pdp11_d (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
const struct real_format pdp11_f_format =
{
encode_pdp11_f,
decode_pdp11_f,
2,
1,
24,
24,
-127,
127,
15,
false,
false,
false,
false,
false
};
const struct real_format pdp11_d_format =
{
encode_pdp11_d,
decode_pdp11_d,
2,
1,
56,
56,
-127,
127,
15,
false,
false,
false,
false,
false
};
static void
encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
(*vax_f_format.encode) (fmt, buf, r);
buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
}
static void
decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
long tbuf;
tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
(*vax_f_format.decode) (fmt, r, &tbuf);
}
static void
encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
(*vax_d_format.encode) (fmt, buf, r);
buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
}
static void
decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
long tbuf[2];
tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16);
tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16);
(*vax_d_format.decode) (fmt, r, tbuf);
}
static rtx find_addr_reg (rtx);
static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int);
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
static bool pdp11_rtx_costs (rtx, int, int, int *);
static bool pdp11_return_in_memory (tree, tree);
#undef TARGET_ASM_BYTE_OP
#define TARGET_ASM_BYTE_OP NULL
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP NULL
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP NULL
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER pdp11_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
#undef TARGET_ASM_OPEN_PAREN
#define TARGET_ASM_OPEN_PAREN "["
#undef TARGET_ASM_CLOSE_PAREN
#define TARGET_ASM_CLOSE_PAREN "]"
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS pdp11_rtx_costs
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory
struct gcc_target targetm = TARGET_INITIALIZER;
int
arith_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
}
int
const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT);
}
int
immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
}
int
expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& abs (INTVAL(op)) > 1
&& abs (INTVAL(op)) <= 4);
}
#ifdef TWO_BSD
static void
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
{
fprintf (stream, "\tjsr r5, csv\n");
if (size)
{
fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
if (size > 2)
fprintf(stream, "\tsub $%#o, sp\n", size - 2);
}
}
#else
static void
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
{
HOST_WIDE_INT fsize = ((size) + 1) & ~1;
int regno;
int via_ac = -1;
fprintf (stream,
"\n\t; /* function prologue %s*/\n",
current_function_name ());
if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
{
fprintf(stream,
"\t;/* switch cpu to double float, single integer */\n");
fprintf(stream, "\tsetd\n");
fprintf(stream, "\tseti\n\n");
}
if (frame_pointer_needed)
{
fprintf(stream, "\tmov r5, -(sp)\n");
fprintf(stream, "\tmov sp, r5\n");
}
else
{
}
if (fsize)
fprintf (stream, "\tsub $%#o, sp\n", fsize);
for (regno = 0; regno < 8; regno++)
if (regs_ever_live[regno] && ! call_used_regs[regno])
if (! ((regno == FRAME_POINTER_REGNUM)
&& frame_pointer_needed))
fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
via_ac = -1;
for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
{
if (LOAD_FPU_REG_P(regno)
&& regs_ever_live[regno]
&& ! call_used_regs[regno])
{
fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
via_ac = regno;
}
if (NO_LOAD_FPU_REG_P(regno)
&& regs_ever_live[regno]
&& ! call_used_regs[regno])
{
if (via_ac == -1)
abort();
fprintf (stream, "\tldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
}
}
fprintf (stream, "\t;/* end of prologue */\n\n");
}
#endif
#ifdef TWO_BSD
static void
pdp11_output_function_epilogue (FILE *stream,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
fprintf (stream, "\t/* SP ignored by cret? */\n");
fprintf (stream, "\tjmp cret\n");
}
#else
static void
pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
{
HOST_WIDE_INT fsize = ((size) + 1) & ~1;
int i, j, k;
int via_ac;
fprintf (stream, "\n\t; /*function epilogue */\n");
if (frame_pointer_needed)
{
regs_ever_live[FRAME_POINTER_REGNUM] = 0;
for (i =7, j = 0 ; i >= 0 ; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
j++;
k = 2*j;
for (i =7 ; i >= 0 ; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
via_ac = FIRST_PSEUDO_REGISTER -1;
for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
via_ac = i;
k += 8;
}
for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
{
if (LOAD_FPU_REG_P(i)
&& regs_ever_live[i]
&& ! call_used_regs[i])
{
fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
k -= 8;
}
if (NO_LOAD_FPU_REG_P(i)
&& regs_ever_live[i]
&& ! call_used_regs[i])
{
if (! LOAD_FPU_REG_P(via_ac))
abort();
fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
k -= 8;
}
}
fprintf(stream, "\tmov r5, sp\n");
fprintf (stream, "\tmov (sp)+, r5\n");
}
else
{
via_ac = FIRST_PSEUDO_REGISTER -1;
for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
if (regs_ever_live[i] && call_used_regs[i])
via_ac = i;
for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
{
if (LOAD_FPU_REG_P(i)
&& regs_ever_live[i]
&& ! call_used_regs[i])
fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
if (NO_LOAD_FPU_REG_P(i)
&& regs_ever_live[i]
&& ! call_used_regs[i])
{
if (! LOAD_FPU_REG_P(via_ac))
abort();
fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
}
}
for (i=7; i >= 0; i--)
if (regs_ever_live[i] && !call_used_regs[i])
fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
if (fsize)
fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
}
fprintf (stream, "\trts pc\n");
fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
}
#endif
static const char *
singlemove_string (rtx *operands)
{
if (operands[1] != const0_rtx)
return "mov %1,%0";
return "clr %0";
}
const char *
output_move_double (rtx *operands)
{
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx addreg0 = 0, addreg1 = 0;
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1])
#if 0
|| GET_CODE (operands[1]) == CONST_DOUBLE
#endif
)
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
if (optype0 == RNDOP || optype1 == RNDOP)
abort ();
if (optype0 == PUSHOP && optype1 == POPOP)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $4,%0", operands);
operands[0] = gen_rtx_MEM (SImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("sub $4,%1", operands);
operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
}
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], HImode, 2);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], HImode, 2);
else if (optype1 == CNSTOP)
{
if (CONSTANT_P (operands[1]))
{
latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
abort();
}
}
else
latehalf[1] = operands[1];
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
operands[1] = latehalf[1];
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1])))
{
if (addreg0)
output_asm_insn ("add $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $2,%0", &addreg1);
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
output_asm_insn ("sub $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $2,%0", &addreg1);
return singlemove_string (operands);
}
output_asm_insn (singlemove_string (operands), operands);
if (addreg0)
output_asm_insn ("add $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $2,%0", &addreg1);
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
output_asm_insn ("sub $2,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $2,%0", &addreg1);
return "";
}
const char *
output_move_quad (rtx *operands)
{
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx addreg0 = 0, addreg1 = 0;
output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1])
|| GET_CODE (operands[1]) == CONST_DOUBLE)
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
if (optype0 == RNDOP || optype1 == RNDOP)
abort ();
if (optype0 == REGOP && optype1 == REGOP)
if (CPU_REG_P(REGNO(operands[0]))
|| CPU_REG_P (REGNO(operands[1])))
abort();
if (optype0 == REGOP || optype1 == REGOP)
{
if (FPU_REG_P(REGNO(operands[0])))
{
if (GET_CODE(operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
if (REAL_VALUES_EQUAL (r, dconst0))
return "{clrd|clrf} %0";
}
return "{ldd|movf} %1, %0";
}
if (FPU_REG_P(REGNO(operands[1])))
return "{std|movf} %1, %0";
}
if (optype0 == PUSHOP && optype1 == POPOP)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $8,%0", operands);
operands[0] = gen_rtx_MEM (DImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("sub $8,%1", operands);
operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
}
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], SImode, 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], SImode, 4);
else if (optype1 == CNSTOP)
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long dval[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (r, dval);
latehalf[1] = GEN_INT (dval[1]);
operands[1] = GEN_INT (dval[0]);
}
else if (GET_CODE(operands[1]) == CONST_INT)
{
latehalf[1] = const0_rtx;
}
else
abort();
}
else
latehalf[1] = operands[1];
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
operands[1] = latehalf[1];
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1])))
{
if (addreg0)
output_asm_insn ("add $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $4,%0", &addreg1);
output_asm_insn(output_move_double(latehalf), latehalf);
if (addreg0)
output_asm_insn ("sub $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $4,%0", &addreg1);
return output_move_double (operands);
}
output_asm_insn (output_move_double (operands), operands);
if (addreg0)
output_asm_insn ("add $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("add $4,%0", &addreg1);
output_asm_insn (output_move_double (latehalf), latehalf);
if (addreg0)
output_asm_insn ("sub $4,%0", &addreg0);
if (addreg1)
output_asm_insn ("sub $4,%0", &addreg1);
return "";
}
static rtx
find_addr_reg (rtx addr)
{
while (GET_CODE (addr) == PLUS)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
addr = XEXP (addr, 0);
if (GET_CODE (XEXP (addr, 1)) == REG)
addr = XEXP (addr, 1);
if (CONSTANT_P (XEXP (addr, 0)))
addr = XEXP (addr, 1);
if (CONSTANT_P (XEXP (addr, 1)))
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) == REG)
return addr;
return 0;
}
void
output_ascii (FILE *file, const char *p, int size)
{
int i;
fprintf (file, "\t.byte ");
for (i = 0; i < size; i++)
{
register int c = p[i];
if (c < 0)
c += 256;
fprintf (file, "%#o", c);
if (i < size - 1)
putc (',', file);
}
putc ('\n', file);
}
void
print_operand_address (FILE *file, register rtx addr)
{
register rtx reg1, reg2, breg, ireg;
rtx offset;
retry:
switch (GET_CODE (addr))
{
case MEM:
if (TARGET_UNIX_ASM)
fprintf (file, "*");
else
fprintf (file, "@");
addr = XEXP (addr, 0);
goto retry;
case REG:
fprintf (file, "(%s)", reg_names[REGNO (addr)]);
break;
case PRE_MODIFY:
case PRE_DEC:
fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
break;
case POST_MODIFY:
case POST_INC:
fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
break;
case PLUS:
reg1 = 0; reg2 = 0;
ireg = 0; breg = 0;
offset = 0;
if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
|| GET_CODE (XEXP (addr, 0)) == MEM)
{
offset = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
|| GET_CODE (XEXP (addr, 1)) == MEM)
{
offset = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) != PLUS)
;
else if (GET_CODE (XEXP (addr, 0)) == MULT)
{
reg1 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == MULT)
{
reg1 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
else if (GET_CODE (XEXP (addr, 0)) == REG)
{
reg1 = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (GET_CODE (XEXP (addr, 1)) == REG)
{
reg1 = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
{
if (reg1 == 0)
reg1 = addr;
else
reg2 = addr;
addr = 0;
}
if (offset != 0)
{
if (addr != 0) abort ();
addr = offset;
}
if (reg1 != 0 && GET_CODE (reg1) == MULT)
{
breg = reg2;
ireg = reg1;
}
else if (reg2 != 0 && GET_CODE (reg2) == MULT)
{
breg = reg1;
ireg = reg2;
}
else if (reg2 != 0 || GET_CODE (addr) == MEM)
{
breg = reg2;
ireg = reg1;
}
else
{
breg = reg1;
ireg = reg2;
}
if (addr != 0)
output_address (addr);
if (breg != 0)
{
if (GET_CODE (breg) != REG)
abort ();
fprintf (file, "(%s)", reg_names[REGNO (breg)]);
}
if (ireg != 0)
{
if (GET_CODE (ireg) == MULT)
ireg = XEXP (ireg, 0);
if (GET_CODE (ireg) != REG)
abort ();
abort();
fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
}
break;
default:
output_addr_const_pdp11 (file, addr);
}
}
static bool
pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
if (aligned_p)
switch (size)
{
case 1:
fprintf (asm_out_file, "\t.byte\t");
output_addr_const_pdp11 (asm_out_file, x);
fprintf (asm_out_file, " /* char */\n");
return true;
case 2:
fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
output_addr_const_pdp11 (asm_out_file, x);
fprintf (asm_out_file, " /* short */\n");
return true;
}
return default_assemble_integer (x, size, aligned_p);
}
static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
{
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 2, 2, 10, 22, 22, 22},
{ 0, 2, 2, 10, 22, 22, 22},
{ 0, 10, 10, 2, 2, 2, 10},
{ 0, 22, 22, 2, 2, 2, 22},
{ 0, 22, 22, 2, 2, 2, 22},
{ 0, 22, 22, 10, 22, 22, 22}
} ;
int
register_move_cost(c1, c2)
enum reg_class c1, c2;
{
return move_costs[(int)c1][(int)c2];
}
static bool
pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
{
switch (code)
{
case CONST_INT:
if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
{
*total = 0;
return true;
}
case CONST:
case LABEL_REF:
case SYMBOL_REF:
*total = 2;
return true;
case CONST_DOUBLE:
*total = 4;
return true;
case MULT:
if (optimize_size)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (11);
return false;
case DIV:
if (optimize_size)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (25);
return false;
case MOD:
if (optimize_size)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (26);
return false;
case ABS:
*total = COSTS_N_INSNS (3);
return false;
case ZERO_EXTEND:
*total = COSTS_N_INSNS (1);
return false;
case SIGN_EXTEND:
if (GET_MODE (x) == HImode)
*total = COSTS_N_INSNS (1);
else if (GET_MODE (x) == SImode)
*total = COSTS_N_INSNS (6);
else
*total = COSTS_N_INSNS (2);
return false;
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
if (optimize_size)
*total = COSTS_N_INSNS (1);
else if (GET_MODE (x) == QImode)
{
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
*total = COSTS_N_INSNS (8);
else
*total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
}
else if (GET_MODE (x) == HImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
if (abs (INTVAL (XEXP (x, 1))) == 1)
*total = COSTS_N_INSNS (1);
else
*total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
}
else
*total = COSTS_N_INSNS (10);
}
else if (GET_MODE (x) == SImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
*total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
else
*total = COSTS_N_INSNS (18);
}
return false;
default:
return false;
}
}
const char *
output_jump(const char *pos, const char *neg, int length)
{
static int x = 0;
static char buf[1000];
#if 0
if (cc_status.flags & CC_IN_FPU)
output_asm_insn("cfcc", NULL);
#endif
switch (length)
{
case 1:
strcpy(buf, pos);
strcat(buf, " %l0");
return buf;
case 3:
sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
x++;
return buf;
default:
abort();
}
}
void
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
{
if (GET_CODE (SET_DEST (exp)) == CC0)
{
cc_status.flags = 0;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
}
else if ((GET_CODE (SET_DEST (exp)) == REG
|| GET_CODE (SET_DEST (exp)) == MEM)
&& GET_CODE (SET_SRC (exp)) != PC
&& (GET_MODE (SET_DEST(exp)) == HImode
|| GET_MODE (SET_DEST(exp)) == QImode)
&& (GET_CODE (SET_SRC(exp)) == PLUS
|| GET_CODE (SET_SRC(exp)) == MINUS
|| GET_CODE (SET_SRC(exp)) == AND
|| GET_CODE (SET_SRC(exp)) == IOR
|| GET_CODE (SET_SRC(exp)) == XOR
|| GET_CODE (SET_SRC(exp)) == NOT
|| GET_CODE (SET_SRC(exp)) == NEG
|| GET_CODE (SET_SRC(exp)) == REG
|| GET_CODE (SET_SRC(exp)) == MEM))
{
cc_status.flags = 0;
cc_status.value1 = SET_SRC (exp);
cc_status.value2 = SET_DEST (exp);
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
&& cc_status.value2
&& GET_CODE (cc_status.value2) == MEM)
cc_status.value2 = 0;
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
}
else if (GET_CODE (SET_DEST (exp)) == REG)
{
if ((cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
cc_status.value1 = 0;
if ((cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
cc_status.value2 = 0;
}
else if (SET_DEST(exp) == pc_rtx)
{
}
else
{
CC_STATUS_INIT;
}
}
int
simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
rtx addr;
if (GET_CODE (op) != MEM)
return FALSE;
#if 0
if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
return FALSE;
#endif
indirection:
addr = XEXP (op, 0);
switch (GET_CODE (addr))
{
case REG:
return 1;
case PRE_DEC:
case POST_INC:
return 0;
case MEM:
if (GET_CODE (XEXP (addr, 0)) == REG)
return 0;
op=addr;
goto indirection;
case CONST_INT:
case LABEL_REF:
case CONST:
case SYMBOL_REF:
return 0;
case PLUS:
return 0;
default:
break;
}
return FALSE;
}
const char *
output_block_move(rtx *operands)
{
static int count = 0;
char buf[200];
if (GET_CODE(operands[2]) == CONST_INT
&& ! optimize_size)
{
if (INTVAL(operands[2]) < 16
&& INTVAL(operands[3]) == 1)
{
register int i;
for (i = 1; i <= INTVAL(operands[2]); i++)
output_asm_insn("movb (%1)+, (%0)+", operands);
return "";
}
else if (INTVAL(operands[2]) < 32)
{
register int i;
for (i = 1; i <= INTVAL(operands[2])/2; i++)
output_asm_insn("mov (%1)+, (%0)+", operands);
return "";
}
}
if (CONSTANT_P(operands[2]) )
{
output_asm_insn("mov %2, %4", operands);
}
else
{
operands[4] = operands[2];
}
switch (INTVAL(operands[3]))
{
case 1:
sprintf(buf, "\nmovestrhi%d:", count);
output_asm_insn(buf, NULL);
output_asm_insn("movb (%1)+, (%0)+", operands);
if (TARGET_45)
{
sprintf(buf, "sob %%4, movestrhi%d", count);
output_asm_insn(buf, operands);
}
else
{
output_asm_insn("dec %4", operands);
sprintf(buf, "bgt movestrhi%d", count);
output_asm_insn(buf, NULL);
}
count ++;
break;
case 2:
generate_compact_code:
output_asm_insn("asr %4", operands);
sprintf(buf, "\nmovestrhi%d:", count);
output_asm_insn(buf, NULL);
output_asm_insn("mov (%1)+, (%0)+", operands);
if (TARGET_45)
{
sprintf(buf, "sob %%4, movestrhi%d", count);
output_asm_insn(buf, operands);
}
else
{
output_asm_insn("dec %4", operands);
sprintf(buf, "bgt movestrhi%d", count);
output_asm_insn(buf, NULL);
}
count ++;
break;
case 4:
if (optimize_size)
goto generate_compact_code;
output_asm_insn("asr %4", operands);
output_asm_insn("asr %4", operands);
sprintf(buf, "\nmovestrhi%d:", count);
output_asm_insn(buf, NULL);
output_asm_insn("mov (%1)+, (%0)+", operands);
output_asm_insn("mov (%1)+, (%0)+", operands);
if (TARGET_45)
{
sprintf(buf, "sob %%4, movestrhi%d", count);
output_asm_insn(buf, operands);
}
else
{
output_asm_insn("dec %4", operands);
sprintf(buf, "bgt movestrhi%d", count);
output_asm_insn(buf, NULL);
}
count ++;
break;
default:
if (optimize_size)
goto generate_compact_code;
output_asm_insn("asr %4", operands);
output_asm_insn("asr %4", operands);
output_asm_insn("asr %4", operands);
sprintf(buf, "\nmovestrhi%d:", count);
output_asm_insn(buf, NULL);
output_asm_insn("mov (%1)+, (%0)+", operands);
output_asm_insn("mov (%1)+, (%0)+", operands);
output_asm_insn("mov (%1)+, (%0)+", operands);
output_asm_insn("mov (%1)+, (%0)+", operands);
if (TARGET_45)
{
sprintf(buf, "sob %%4, movestrhi%d", count);
output_asm_insn(buf, operands);
}
else
{
output_asm_insn("dec %4", operands);
sprintf(buf, "bgt movestrhi%d", count);
output_asm_insn(buf, NULL);
}
count ++;
break;
;
}
return "";
}
int
legitimate_address_p (enum machine_mode mode, rtx address)
{
GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
return 0;
win:
return 1;
}
int
legitimate_const_double_p (rtx address)
{
REAL_VALUE_TYPE r;
long sval[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, address);
REAL_VALUE_TO_TARGET_DOUBLE (r, sval);
if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
return 1;
return 0;
}
void
output_addr_const_pdp11 (FILE *file, rtx x)
{
char buf[256];
restart:
switch (GET_CODE (x))
{
case PC:
if (flag_pic)
putc ('.', file);
else
abort ();
break;
case SYMBOL_REF:
assemble_name (file, XSTR (x, 0));
break;
case LABEL_REF:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
assemble_name (file, buf);
break;
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
assemble_name (file, buf);
break;
case CONST_INT:
fprintf (file, "%#ho", (unsigned short) INTVAL (x));
break;
case CONST:
output_addr_const_pdp11 (file, XEXP (x, 0));
break;
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
{
if (CONST_DOUBLE_HIGH (x))
abort ();
else
fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
}
else
output_operand_lossage ("floating constant misused");
break;
case PLUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
output_addr_const_pdp11 (file, XEXP (x, 1));
if (INTVAL (XEXP (x, 0)) >= 0)
fprintf (file, "+");
output_addr_const_pdp11 (file, XEXP (x, 0));
}
else
{
output_addr_const_pdp11 (file, XEXP (x, 0));
if (INTVAL (XEXP (x, 1)) >= 0)
fprintf (file, "+");
output_addr_const_pdp11 (file, XEXP (x, 1));
}
break;
case MINUS:
x = simplify_subtraction (x);
if (GET_CODE (x) != MINUS)
goto restart;
output_addr_const_pdp11 (file, XEXP (x, 0));
fprintf (file, "-");
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < 0)
{
fprintf (file, targetm.asm_out.open_paren);
output_addr_const_pdp11 (file, XEXP (x, 1));
fprintf (file, targetm.asm_out.close_paren);
}
else
output_addr_const_pdp11 (file, XEXP (x, 1));
break;
case ZERO_EXTEND:
case SIGN_EXTEND:
output_addr_const_pdp11 (file, XEXP (x, 0));
break;
default:
output_operand_lossage ("invalid expression as operand");
}
}
static bool
pdp11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
return (TYPE_MODE (type) == DImode
|| (TYPE_MODE (type) == DFmode && ! TARGET_AC0));
}