summaryrefslogtreecommitdiff
path: root/gcc/config/pdp11/pdp11.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/pdp11/pdp11.c')
-rwxr-xr-xgcc/config/pdp11/pdp11.c1415
1 files changed, 0 insertions, 1415 deletions
diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c
deleted file mode 100755
index 9bf69dd..0000000
--- a/gcc/config/pdp11/pdp11.c
+++ /dev/null
@@ -1,1415 +0,0 @@
-/* Subroutines for gcc2 for pdp11.
- Copyright (C) 1994, 1995, 1996, 1997 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)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#include "config.h"
-#include <stdio.h>
-#include "rtl.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "real.h"
-#include "insn-config.h"
-#include "conditions.h"
-#include "insn-flags.h"
-#include "output.h"
-#include "insn-attr.h"
-#include "flags.h"
-
-/*
-#define FPU_REG_P(X) ((X)>=8 && (X)<14)
-#define CPU_REG_P(X) ((X)>=0 && (X)<8)
-*/
-
-/* this is the current value returned by the macro FIRST_PARM_OFFSET
- defined in tm.h */
-int current_first_parm_offset;
-
-/* This is where the condition code register lives. */
-/* rtx cc0_reg_rtx; - no longer needed? */
-
-static rtx find_addr_reg ();
-
-/* Nonzero if OP is a valid second operand for an arithmetic insn. */
-
-int
-arith_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
-}
-
-int
-const_immediate_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (GET_CODE (op) == CONST_INT);
-}
-
-int
-immediate15_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
-}
-
-int
-expand_shift_operand (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return (GET_CODE (op) == CONST_INT
- && abs (INTVAL(op)) > 1
- && abs (INTVAL(op)) <= 4);
-}
-
-/*
- stream is a stdio stream to output the code to.
- size is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This macro is responsible for
- knowing which registers should not be saved even if used.
-*/
-
-void
-output_function_prologue(stream, size)
- FILE *stream;
- int size;
-{
- int fsize = ((size) + 1) & ~1;
- int regno, nregs, i;
- int offset = 0;
-
- int via_ac = -1;
-
- fprintf (stream, "\n\t; /* function prologue %s*/\n", current_function_name);
-
- /* 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)
- {
- 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 fp, -(sp)\n");
- fprintf(stream, "\tmov sp, fp\n");
- }
- else
- {
- /* DON'T SAVE FP */
- }
-
- /* make frame */
- if (fsize)
- fprintf (stream, "\tsub $%d, sp\n", fsize);
-
- /* save CPU registers */
- 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]);
- /* fpu regs saving */
-
- /* via_ac specifies the ac to use for saving ac4, ac5 */
- via_ac = -1;
-
- for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
- {
- /* ac0 - ac3 */
- if (LOAD_FPU_REG_P(regno)
- && regs_ever_live[regno]
- && ! call_used_regs[regno])
- {
- fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
- via_ac = regno;
- }
-
- /* maybe make ac4, ac5 call used regs?? */
- /* ac4 - ac5 */
- if (NO_LOAD_FPU_REG_P(regno)
- && regs_ever_live[regno]
- && ! call_used_regs[regno])
- {
- if (via_ac == -1)
- abort();
-
- fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
- fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
- }
- }
-
- fprintf (stream, "\t;/* end of prologue */\n\n");
-}
-
-/*
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only. This is mandatory because
- of alloca; we also take advantage of it to omit stack adjustments
- before returning. */
-
-/* maybe we can make leaf functions faster by switching to the
- second register file - this way we don't have to save regs!
- leaf functions are ~ 50% of all functions (dynamically!)
-
- set/clear bit 11 (dec. 2048) of status word for switching register files -
- but how can we do this? the pdp11/45 manual says bit may only
- be set (p.24), but not cleared!
-
- switching to kernel is probably more expensive, so we'll leave it
- like this and not use the second set of registers...
-
- maybe as option if you want to generate code for kernel mode? */
-
-
-void
-output_function_epilogue(stream, size)
- FILE *stream;
- int size;
-{
- extern int may_call_alloca;
-
- int fsize = ((size) + 1) & ~1;
- int nregs, regno, i, j, k, adjust_fp;
-
- int via_ac;
-
- fprintf (stream, "\n\t; /*function epilogue */\n");
-
- if (frame_pointer_needed)
- {
- /* hope this is safe - m68k does it also .... */
- 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++;
-
- /* remember # of pushed bytes for CPU regs */
- k = 2*j;
-
- 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]);
-
- /* get ACs */
- 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, "\tfldd %d(fp), %s\n", -fsize-k, 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, "\tfldd %d(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 fp, sp\n");
- fprintf (stream, "\tmov (sp)+, fp\n");
- }
- else
- {
- via_ac = FIRST_PSEUDO_REGISTER -1;
-
- /* get ACs */
- 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, "\tfldd (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, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
- fprintf(stream, "\tfstd %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 $%d, sp\n", fsize);
- }
-
- fprintf (stream, "\trts pc\n");
- fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
-}
-
-/* Return the best assembler insn template
- for moving operands[1] into operands[0] as a fullword. */
-static char *
-singlemove_string (operands)
- rtx *operands;
-{
- if (operands[1] != const0_rtx)
- return "mov %1,%0";
-
- return "clr %0";
-}
-
-
-/* Output assembler code to perform a doubleword move insn
- with operands OPERANDS. */
-
-char *
-output_move_double (operands)
- rtx *operands;
-{
- enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
- rtx latehalf[2];
- rtx addreg0 = 0, addreg1 = 0;
-
- /* First classify both 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]))
-#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;
-
- /* Check for the cases that the operand constraints are not
- supposed to allow to happen. Abort if we get one,
- because generating code for these cases is painful. */
-
- if (optype0 == RNDOP || optype1 == RNDOP)
- abort ();
-
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
-
- 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 an operand is an unoffsettable memory ref, find a register
- we can increment temporarily to make it refer to the second word. */
-
- if (optype0 == MEMOP)
- addreg0 = find_addr_reg (XEXP (operands[0], 0));
-
- if (optype1 == MEMOP)
- addreg1 = find_addr_reg (XEXP (operands[1], 0));
-
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- if (optype0 == REGOP)
- 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);
- else if (optype1 == OFFSOP)
- latehalf[1] = adj_offsettable_operand (operands[1], 2);
- else if (optype1 == CNSTOP)
- {
- if (CONSTANT_P (operands[1]))
- {
- /* 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_INT (INTVAL(operands[1])>>16);
- operands[1] = GEN_INT (INTVAL(operands[1])&0xff);
- }
- else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- /* immediate 32 bit values not allowed */
- abort();
- }
- }
- else
- latehalf[1] = operands[1];
-
- /* If insn is effectively movd N(sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1 (which is N+4(sp))
- for the low word as well, to compensate for the first decrement of sp. */
- 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 one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && REGNO (operands[0]) == REGNO (latehalf[1])))
- {
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("add $2,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add $2,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("sub $2,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("sub $2,%0", &addreg1);
-
- /* Do low-numbered word. */
- return singlemove_string (operands);
- }
-
- /* Normal case: do the two words, low-numbered first. */
-
- output_asm_insn (singlemove_string (operands), operands);
-
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("add $2,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add $2,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (singlemove_string (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("sub $2,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("sub $2,%0", &addreg1);
-
- return "";
-}
-/* Output assembler code to perform a quadword move insn
- with operands OPERANDS. */
-
-char *
-output_move_quad (operands)
- 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;
-
- /* Check for the cases that the operand constraints are not
- supposed to allow to happen. Abort if we get one,
- because generating code for these cases is painful. */
-
- if (optype0 == RNDOP || optype1 == RNDOP)
- abort ();
-
- /* check if we move a CPU reg to an FPU reg, or vice versa! */
- if (optype0 == REGOP && optype1 == REGOP)
- /* bogus - 64 bit cannot reside in CPU! */
- if (CPU_REG_P(REGNO(operands[0]))
- || CPU_REG_P (REGNO(operands[1])))
- abort();
-
- if (optype0 == REGOP || optype1 == REGOP)
- {
- /* check for use of clrd????
- if you ever allow ac4 and ac5 (now we require secondary load)
- you must check whether
- you want to load into them or store from them -
- then dump ac0 into $help$ movce ac4/5 to ac0, do the
- store from ac0, and restore ac0 - if you can find
- an unused ac[0-3], use that and you save a store and a load!*/
-
- if (FPU_REG_P(REGNO(operands[0])))
- {
- if (GET_CODE(operands[1]) == CONST_DOUBLE)
- {
- union { double d; int i[2]; } u;
- u.i[0] = CONST_DOUBLE_LOW (operands[1]);
- u.i[1] = CONST_DOUBLE_HIGH (operands[1]);
-
- if (u.d == 0.0)
- return "clrd %0";
- }
-
- return "ldd %1, %0";
- }
-
- if (FPU_REG_P(REGNO(operands[1])))
- return "std %1, %0";
- }
-
- /* If one operand is decrementing and one is incrementing
- decrement the former register explicitly
- and change that operand into ordinary indexing. */
-
- 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 an operand is an unoffsettable memory ref, find a register
- we can increment temporarily to make it refer to the second word. */
-
- if (optype0 == MEMOP)
- addreg0 = find_addr_reg (XEXP (operands[0], 0));
-
- if (optype1 == MEMOP)
- addreg1 = find_addr_reg (XEXP (operands[1], 0));
-
- /* Ok, we can do one word at a time.
- Normally we do the low-numbered word first,
- but if either operand is autodecrementing then we
- do the high-numbered word first.
-
- In either case, set up in LATEHALF the operands to use
- for the high-numbered word and in some cases alter the
- operands in OPERANDS to be suitable for the low-numbered word. */
-
- if (optype0 == REGOP)
- 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);
- else if (optype1 == OFFSOP)
- latehalf[1] = adj_offsettable_operand (operands[1], 4);
- else if (optype1 == CNSTOP)
- {
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- /* floats only. not yet supported!
-
- -- compute it into PDP float format, - internally,
- just use IEEE and ignore possible problems ;-)
-
- we might get away with it !!!! */
-
- abort();
-
-#ifndef HOST_WORDS_BIG_ENDIAN
- 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_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];
-
- /* If insn is effectively movd N(sp),-(sp) then we will do the
- high word first. We should use the adjusted operand 1 (which is N+4(sp))
- for the low word as well, to compensate for the first decrement of sp. */
- 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 one or both operands autodecrementing,
- do the two words, high-numbered first. */
-
- /* Likewise, the first move would clobber the source of the second one,
- do them in the other order. This happens only for registers;
- such overlap can't happen in memory unless the user explicitly
- sets it up, and that is an undefined circumstance. */
-
- if (optype0 == PUSHOP || optype1 == PUSHOP
- || (optype0 == REGOP && optype1 == REGOP
- && REGNO (operands[0]) == REGNO (latehalf[1])))
- {
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("add $4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add $4,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn(output_move_double(latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("sub $4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("sub $4,%0", &addreg1);
-
- /* Do low-numbered word. */
- return output_move_double (operands);
- }
-
- /* Normal case: do the two words, low-numbered first. */
-
- output_asm_insn (output_move_double (operands), operands);
-
- /* Make any unoffsettable addresses point at high-numbered word. */
- if (addreg0)
- output_asm_insn ("add $4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("add $4,%0", &addreg1);
-
- /* Do that word. */
- output_asm_insn (output_move_double (latehalf), latehalf);
-
- /* Undo the adds we just did. */
- if (addreg0)
- output_asm_insn ("sub $4,%0", &addreg0);
- if (addreg1)
- output_asm_insn ("sub $4,%0", &addreg1);
-
- return "";
-}
-
-
-/* Return a REG that occurs in ADDR with coefficient 1.
- ADDR can be effectively incremented by incrementing REG. */
-
-static rtx
-find_addr_reg (addr)
- 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;
-}
-
-/* Output an ascii string. */
-output_ascii (file, p, size)
- FILE *file;
- char *p;
- int size;
-{
- int i;
-
- 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 \"");
- }
- }
- fprintf (file, "\"\n");
-}
-
-
-/* --- stole from out-vax, needs changes */
-
-print_operand_address (file, addr)
- FILE *file;
- register rtx addr;
-{
- register rtx reg1, reg2, breg, ireg;
- rtx offset;
-
- retry:
-
- switch (GET_CODE (addr))
- {
- case MEM:
- fprintf (file, "@");
- addr = XEXP (addr, 0);
- goto retry;
-
- case REG:
- fprintf (file, "(%s)", reg_names[REGNO (addr)]);
- break;
-
- case PRE_DEC:
- fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
- break;
-
- 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 (file, addr);
- }
-}
-
-/* register move costs, indexed by regs */
-
-static int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
-{
- /* NO MUL GEN LFPU NLFPU FPU ALL */
-
-/* NO */ { 0, 0, 0, 0, 0, 0, 0},
-/* MUL */ { 0, 2, 2, 10, 22, 22, 22},
-/* GEN */ { 0, 2, 2, 10, 22, 22, 22},
-/* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
-/* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
-/* FPU */ { 0, 22, 22, 2, 2, 2, 22},
-/* ALL */ { 0, 22, 22, 10, 22, 22, 22}
-} ;
-
-
-/* -- note that some moves are tremendously expensive,
- because they require lots of tricks! do we have to
- charge the costs incurred by secondary reload class
- -- as we do here with 22 -- or not ? */
-
-int
-register_move_cost(c1, c2)
- enum reg_class c1, c2;
-{
- return move_costs[(int)c1][(int)c2];
-}
-
-char *
-output_jump(pos, neg, length)
- int length;
- char *pos, *neg;
-{
- static int x = 0;
-
- static char buf[1000];
-
-#if 0
-/* currently we don't need this, because the tstdf and cmpdf
- copy the condition code immediately, and other float operations are not
- yet recognized as changing the FCC - if so, then the length-cost of all
- jump insns increases by one, because we have to potentially copy the
- FCC! */
- 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(exp, insn)
- rtx exp;
- rtx insn;
-{
- if (GET_CODE (SET_DEST (exp)) == CC0)
- {
- cc_status.flags = 0;
- cc_status.value1 = SET_DEST (exp);
- cc_status.value2 = SET_SRC (exp);
-
-/*
- if (GET_MODE(SET_SRC(exp)) == DFmode)
- cc_status.flags |= CC_IN_FPU;
-*/
- }
- 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)
- /* what's this ? */
- {
- 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)
- {
- /* jump */
- }
- else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
- {
- /* the last else is a bit paranoiac, but since nearly all instructions
- play with condition codes, it's reasonable! */
-
- CC_STATUS_INIT; /* paranoia*/
- }
-}
-
-
-int simple_memory_operand(op, mode)
- rtx op;
- enum machine_mode mode;
-{
- rtx addr, plus0, plus1;
- int offset = 0;
-
- /* Eliminate non-memory operations */
- if (GET_CODE (op) != MEM)
- return FALSE;
-
-#if 0
- /* dword operations really put out 2 instructions, so eliminate them. */
- if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
- return FALSE;
-#endif
-
- /* Decode the address now. */
-
- indirection:
-
- addr = XEXP (op, 0);
-
- switch (GET_CODE (addr))
- {
- case REG:
- /* (R0) - no extra cost */
- return 1;
-
- case PRE_DEC:
- case POST_INC:
- /* -(R0), (R0)+ - cheap! */
- return 0;
-
- case MEM:
- /* cheap - is encoded in addressing mode info!
-
- -- except for @(R0), which has to be @0(R0) !!! */
-
- if (GET_CODE (XEXP (addr, 0)) == REG)
- return 0;
-
- op=addr;
- goto indirection;
-
- case CONST_INT:
- case LABEL_REF:
- case CONST:
- case SYMBOL_REF:
- /* @#address - extra cost */
- return 0;
-
- case PLUS:
- /* X(R0) - extra cost */
- return 0;
- }
-
- return FALSE;
-}
-
-
-/*
- * output a block move:
- *
- * operands[0] ... to
- * operands[1] ... from
- * operands[2] ... length
- * operands[3] ... alignment
- * operands[4] ... scratch register
- */
-
-
-char *
-output_block_move(operands)
- 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);
-
- /* may I assume that moved quantity is
- multiple of alignment ???
-
- I HOPE SO !
- */
-
- return "";
- }
-
-
- /* can do other clever things, maybe... */
- }
-
- if (CONSTANT_P(operands[2]) )
- {
- /* just move count to scratch */
- output_asm_insn("mov %2, %4", operands);
- }
- else
- {
- /* just clobber the register */
- operands[4] = operands[2];
- }
-
-
- /* switch over alignment */
- switch (INTVAL(operands[3]))
- {
- case 1:
-
- /*
- x:
- movb (%1)+, (%0)+
-
- if (TARGET_45)
- sob %4,x
- else
- dec %4
- bgt x
-
- */
-
- 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:
-
- /*
- asr %4
-
- x:
-
- mov (%1)+, (%0)+
-
- if (TARGET_45)
- sob %4, x
- else
- dec %4
- bgt x
- */
-
- 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:
-
- /*
-
- asr %4
- asr %4
-
- x:
-
- mov (%1)+, (%0)+
- mov (%1)+, (%0)+
-
- if (TARGET_45)
- sob %4, x
- else
- dec %4
- bgt x
- */
-
- 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:
-
- /*
-
- asr %4
- asr %4
- asr %4
-
- x:
-
- mov (%1)+, (%0)+
- mov (%1)+, (%0)+
- mov (%1)+, (%0)+
- mov (%1)+, (%0)+
-
- if (TARGET_45)
- sob %4, x
- else
- dec %4
- bgt x
- */
-
-
- 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 "";
-}
-
-/* for future use */
-int
-comparison_operator_index(op)
- rtx op;
-{
- switch (GET_CODE(op))
- {
- case NE:
- return 0;
-
- case EQ:
- return 1;
-
- case GE:
- return 2;
-
- case GT:
- return 3;
-
- case LE:
- return 4;
-
- case LT:
- return 5;
-
- case GEU:
- return 6;
-
- case GTU:
- return 7;
-
- case LEU:
- return 8;
-
- case LTU:
- return 9;
-
- default:
- return -1;
- }
-}
-
-/* tests whether the rtx is a comparison operator */
-int
-comp_operator (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- return comparison_operator_index(op) >= 0;
-}
-
-
-int
-legitimate_address_p (mode, address)
- enum machine_mode mode;
- rtx address;
-{
-/* #define REG_OK_STRICT */
- GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
-
- return 0;
-
- win:
- return 1;
-
-/* #undef REG_OK_STRICT */
-}