/* Subroutines for gcc2 for pdp11.
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999
+ Free Software Foundation, Inc.
Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#ifndef FILE
-#include <stdio.h>
-#endif
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
+#include "function.h"
#include "output.h"
#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "tree.h"
+#include "tm_p.h"
/*
#define FPU_REG_P(X) ((X)>=8 && (X)<14)
/* This is where the condition code register lives. */
/* rtx cc0_reg_rtx; - no longer needed? */
-static rtx find_addr_reg ();
+static rtx find_addr_reg PARAMS ((rtx));
+static const char *singlemove_string PARAMS ((rtx *));
/* Nonzero if OP is a valid second operand for an arithmetic insn. */
int
const_immediate_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT);
}
int
immediate15_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
}
int
expand_shift_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT
&& abs (INTVAL(op)) > 1
FILE *stream;
int size;
{
- extern char call_used_regs[];
- extern int frame_pointer_needed;
-
int fsize = ((size) + 1) & ~1;
- int regno, nregs, i;
- int offset = 0;
+ int regno;
int via_ac = -1;
/* if we are outputting code for main,
the switch FPU to right mode if TARGET_FPU */
- if ( (strcmp ("main", current_function_name) == 0)
- && TARGET_FPU)
+ 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");
/* make frame */
if (fsize)
- fprintf (stream, "\tsub $%d, sp\n", fsize);
+ fprintf (stream, "\tsub $%o, sp\n", fsize);
/* save CPU registers */
for (regno = 0; regno < 8; regno++)
FILE *stream;
int size;
{
- extern char call_used_regs[];
- extern int may_call_alloca;
-
int fsize = ((size) + 1) & ~1;
- int nregs, regno, i, j, k, adjust_fp;
+ int i, j, k;
int via_ac;
for (i =7 ; i >= 0 ; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
- fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
+ fprintf(stream, "\tmov %o(fp), %s\n",-fsize-2*j--, reg_names[i]);
/* get ACs */
via_ac = FIRST_PSEUDO_REGISTER -1;
&& regs_ever_live[i]
&& ! call_used_regs[i])
{
- fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
+ fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[i]);
k -= 8;
}
if (! LOAD_FPU_REG_P(via_ac))
abort();
- fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
+ fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[via_ac]);
fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
k -= 8;
}
fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
if (fsize)
- fprintf((stream), "\tadd $%d, sp\n", fsize);
+ fprintf((stream), "\tadd $%o, sp\n", fsize);
}
fprintf (stream, "\trts pc\n");
/* Return the best assembler insn template
for moving operands[1] into operands[0] as a fullword. */
-static char *
+static const char *
singlemove_string (operands)
rtx *operands;
{
/* Output assembler code to perform a doubleword move insn
with operands OPERANDS. */
-char *
+const char *
output_move_double (operands)
rtx *operands;
{
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $4,%0", operands);
- operands[0] = gen_rtx (MEM, SImode, operands[0]);
+ 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]);
+ operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
}
operands in OPERANDS to be suitable for the low-numbered word. */
if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
+ latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adj_offsettable_operand (operands[0], 2);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
- latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
+ latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adj_offsettable_operand (operands[1], 2);
else if (optype1 == CNSTOP)
/* now the mess begins, high word is in lower word???
that's what ashc makes me think, but I don't remember :-( */
- latehalf[1] = gen_rtx(CONST_INT, VOIDmode,
- INTVAL(operands[1])>>16);
- operands[1] = gen_rtx(CONST_INT, VOIDmode,
- INTVAL(operands[1])&0xff);
+ latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
+ operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
/* Output assembler code to perform a quadword move insn
with operands OPERANDS. */
-char *
+const char *
output_move_quad (operands)
rtx *operands;
{
u.i[1] = CONST_DOUBLE_HIGH (operands[1]);
if (u.d == 0.0)
- return "clrd %0";
+ return "{clrd|clrf} %0";
}
- return "ldd %1, %0";
+ return "{ldd|movf} %1, %0";
}
if (FPU_REG_P(REGNO(operands[1])))
- return "std %1, %0";
+ return "{std|movf} %1, %0";
}
/* If one operand is decrementing and one is incrementing
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub $8,%0", operands);
- operands[0] = gen_rtx (MEM, DImode, operands[0]);
+ 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]);
+ operands[1] = gen_rtx_MEM (SImode, operands[1]);
optype1 = OFFSOP;
}
operands in OPERANDS to be suitable for the low-numbered word. */
if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
+ latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
else if (optype0 == OFFSOP)
latehalf[0] = adj_offsettable_operand (operands[0], 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
- latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
+ latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
else if (optype1 == OFFSOP)
latehalf[1] = adj_offsettable_operand (operands[1], 4);
else if (optype1 == CNSTOP)
abort();
#ifndef HOST_WORDS_BIG_ENDIAN
- latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_LOW (operands[1]));
- operands[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_HIGH (operands[1]));
+ latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
+ operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
#else /* HOST_WORDS_BIG_ENDIAN */
- latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_HIGH (operands[1]));
- operands[1] = gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_LOW (operands[1]));
+ latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
#endif /* HOST_WORDS_BIG_ENDIAN */
}
+ else if (GET_CODE(operands[1]) == CONST_INT)
+ {
+ latehalf[1] = GEN_INT (0);
+ }
+ else
+ abort();
}
else
latehalf[1] = operands[1];
}
\f
/* Output an ascii string. */
+void
output_ascii (file, p, size)
FILE *file;
- char *p;
+ const char *p;
int size;
{
int i;
- fprintf (file, "\t.byte \"");
+ /* This used to output .byte "string", which doesn't work with the UNIX
+ assembler and I think not with DEC ones either. */
+ fprintf (file, "\t.byte ");
for (i = 0; i < size; i++)
{
register int c = p[i];
- if (c == '\"' || c == '\\')
- putc ('\\', file);
- if (c >= ' ' && c < 0177)
- putc (c, file);
- else
- {
- fprintf (file, "\\%03o", c);
- /* After an octal-escape, if a digit follows,
- terminate one string constant and start another.
- The Vax assembler fails to stop reading the escape
- after three digits, so this is the only way we
- can get it to parse the data properly. */
- if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
- fprintf (file, "\"\n\tstring \"");
- }
+ if (c < 0)
+ c += 256;
+ fprintf (file, "%o", c);
+ if (i < size - 1)
+ putc (',', file);
}
- fprintf (file, "\"\n");
+ putc ('\n', file);
}
/* --- stole from out-vax, needs changes */
+void
print_operand_address (file, addr)
FILE *file;
register rtx addr;
switch (GET_CODE (addr))
{
case MEM:
- fprintf (file, "@");
+ if (TARGET_UNIX_ASM)
+ fprintf (file, "*");
+ else
+ fprintf (file, "@");
addr = XEXP (addr, 0);
goto retry;
break;
default:
- output_addr_const (file, addr);
+ output_addr_const_pdp11 (file, addr);
}
}
return move_costs[(int)c1][(int)c2];
}
-char *
+const char *
output_jump(pos, neg, length)
+ const char *pos, *neg;
int length;
- char *pos, *neg;
{
static int x = 0;
void
notice_update_cc_on_set(exp, insn)
rtx exp;
- rtx insn;
+ rtx insn ATTRIBUTE_UNUSED;
{
if (GET_CODE (SET_DEST (exp)) == CC0)
{
}
-int simple_memory_operand(op, mode)
- rtx op;
- enum machine_mode mode;
+int
+simple_memory_operand(op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- rtx addr, plus0, plus1;
- int offset = 0;
+ rtx addr;
/* Eliminate non-memory operations */
if (GET_CODE (op) != MEM)
case PLUS:
/* X(R0) - extra cost */
return 0;
+
+ default:
+ break;
}
return FALSE;
*/
-char *
+const char *
output_block_move(operands)
rtx *operands;
{
char buf[200];
if (GET_CODE(operands[2]) == CONST_INT
- && TARGET_TIME)
+ && ! optimize_size)
{
if (INTVAL(operands[2]) < 16
&& INTVAL(operands[3]) == 1)
bgt x
*/
- if (TARGET_SPACE)
+ if (optimize_size)
goto generate_compact_code;
output_asm_insn("asr %4", operands);
*/
- if (TARGET_SPACE)
+ if (optimize_size)
goto generate_compact_code;
output_asm_insn("asr %4", operands);
int
comp_operator (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return comparison_operator_index(op) >= 0;
}
/* #undef REG_OK_STRICT */
}
+
+/* A copy of output_addr_const modified for pdp11 expression syntax.
+ output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
+ use, and for debugging output, which we don't support with this port either.
+ So this copy should get called whenever needed.
+*/
+void
+output_addr_const_pdp11 (file, x)
+ 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:
+ /* Should we check for constants which are too big? Maybe cutting
+ them off to 16 bits is OK? */
+ fprintf (file, "%ho", (unsigned short) INTVAL (x));
+ break;
+
+ case CONST:
+ /* This used to output parentheses around the expression,
+ but that does not work on the 386 (either ATT or BSD assembler). */
+ output_addr_const_pdp11 (file, XEXP (x, 0));
+ break;
+
+ case CONST_DOUBLE:
+ if (GET_MODE (x) == VOIDmode)
+ {
+ /* We can use %o if the number is one word and positive. */
+ if (CONST_DOUBLE_HIGH (x))
+ abort (); /* Should we just silently drop the high part? */
+ else
+ fprintf (file, "%ho", (unsigned short) CONST_DOUBLE_LOW (x));
+ }
+ else
+ /* We can't handle floating point constants;
+ PRINT_OPERAND must handle them. */
+ output_operand_lossage ("floating constant misused");
+ break;
+
+ case PLUS:
+ /* Some assemblers need integer constants to appear last (eg masm). */
+ 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:
+ /* Avoid outputting things like x-x or x+5-x,
+ since some assemblers can't handle that. */
+ 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, ASM_OPEN_PAREN);
+ output_addr_const_pdp11 (file, XEXP (x, 1));
+ fprintf (file, ASM_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");
+ }
+}