summaryrefslogtreecommitdiff
path: root/gcc/config/vax/vax.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/vax/vax.c')
-rwxr-xr-xgcc/config/vax/vax.c837
1 files changed, 0 insertions, 837 deletions
diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c
deleted file mode 100755
index bac442a..0000000
--- a/gcc/config/vax/vax.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/* Subroutines for insn-output.c for Vax.
- Copyright (C) 1987, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
-
-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 2, 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"
-#ifdef VMS_TARGET
-#include "tree.h"
-#endif
-
-/* This is like nonimmediate_operand with a restriction on the type of MEM. */
-
-void
-split_quadword_operands (operands, low, n)
- rtx *operands, *low;
- int n;
-{
- int i;
- /* Split operands. */
-
- low[0] = low[1] = low[2] = 0;
- for (i = 0; i < 3; i++)
- {
- if (low[i])
- /* it's already been figured out */;
- else if (GET_CODE (operands[i]) == MEM
- && (GET_CODE (XEXP (operands[i], 0)) == POST_INC))
- {
- rtx addr = XEXP (operands[i], 0);
- operands[i] = low[i] = gen_rtx (MEM, SImode, addr);
- if (which_alternative == 0 && i == 0)
- {
- addr = XEXP (operands[i], 0);
- operands[i+1] = low[i+1] = gen_rtx (MEM, SImode, addr);
- }
- }
- else
- {
- low[i] = operand_subword (operands[i], 0, 0, DImode);
- operands[i] = operand_subword (operands[i], 1, 0, DImode);
- }
- }
-}
-
-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:
- /* There can be either two or three things added here. One must be a
- REG. One can be either a REG or a MULT of a REG and an appropriate
- constant, and the third can only be a constant or a MEM.
-
- We get these two or three things and put the constant or MEM in
- OFFSET, the MULT or REG in IREG, and the REG in BREG. If we have
- a register and can't tell yet if it is a base or index register,
- put it into REG1. */
-
- reg1 = 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);
- }
- else if (GET_CODE (XEXP (addr, 1)) == MULT)
- {
- ireg = XEXP (addr, 1);
- addr = XEXP (addr, 0);
- }
- else if (GET_CODE (XEXP (addr, 0)) == MULT)
- {
- ireg = XEXP (addr, 0);
- addr = XEXP (addr, 1);
- }
- else if (GET_CODE (XEXP (addr, 1)) == REG)
- {
- 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
- abort ();
-
- if (GET_CODE (addr) == REG)
- {
- if (reg1)
- ireg = addr;
- else
- reg1 = addr;
- }
- else if (GET_CODE (addr) == MULT)
- ireg = addr;
- else if (GET_CODE (addr) == PLUS)
- {
- if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
- || GET_CODE (XEXP (addr, 0)) == MEM)
- {
- if (offset)
- {
- if (GET_CODE (offset) == CONST_INT)
- offset = plus_constant (XEXP (addr, 0), INTVAL (offset));
- else if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
- offset = plus_constant (offset, INTVAL (XEXP (addr, 0)));
- else
- abort ();
- }
- offset = XEXP (addr, 0);
- }
- else if (GET_CODE (XEXP (addr, 0)) == REG)
- {
- if (reg1)
- ireg = reg1, breg = XEXP (addr, 0), reg1 = 0;
- else
- reg1 = XEXP (addr, 0);
- }
- else if (GET_CODE (XEXP (addr, 0)) == MULT)
- {
- if (ireg)
- abort ();
- ireg = XEXP (addr, 0);
- }
- else
- abort ();
-
- if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
- || GET_CODE (XEXP (addr, 1)) == MEM)
- {
- if (offset)
- {
- if (GET_CODE (offset) == CONST_INT)
- offset = plus_constant (XEXP (addr, 1), INTVAL (offset));
- else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
- offset = plus_constant (offset, INTVAL (XEXP (addr, 1)));
- else
- abort ();
- }
- offset = XEXP (addr, 1);
- }
- else if (GET_CODE (XEXP (addr, 1)) == REG)
- {
- if (reg1)
- ireg = reg1, breg = XEXP (addr, 1), reg1 = 0;
- else
- reg1 = XEXP (addr, 1);
- }
- else if (GET_CODE (XEXP (addr, 1)) == MULT)
- {
- if (ireg)
- abort ();
- ireg = XEXP (addr, 1);
- }
- else
- abort ();
- }
- else
- abort ();
-
- /* If REG1 is non-zero, figure out if it is a base or index register. */
- if (reg1)
- {
- if (breg != 0 || (offset && GET_CODE (offset) == MEM))
- {
- if (ireg)
- abort ();
- ireg = reg1;
- }
- else
- breg = reg1;
- }
-
- if (offset != 0)
- output_address (offset);
-
- if (breg != 0)
- 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 ();
- fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
- }
- break;
-
- default:
- output_addr_const (file, addr);
- }
-}
-
-char *
-rev_cond_name (op)
- rtx op;
-{
- switch (GET_CODE (op))
- {
- case EQ:
- return "neq";
- case NE:
- return "eql";
- case LT:
- return "geq";
- case LE:
- return "gtr";
- case GT:
- return "leq";
- case GE:
- return "lss";
- case LTU:
- return "gequ";
- case LEU:
- return "gtru";
- case GTU:
- return "lequ";
- case GEU:
- return "lssu";
-
- default:
- abort ();
- }
-}
-
-int
-vax_float_literal(c)
- register rtx c;
-{
- register enum machine_mode mode;
- int i;
- union {double d; int i[2];} val;
-
- if (GET_CODE (c) != CONST_DOUBLE)
- return 0;
-
- mode = GET_MODE (c);
-
- if (c == const_tiny_rtx[(int) mode][0]
- || c == const_tiny_rtx[(int) mode][1]
- || c == const_tiny_rtx[(int) mode][2])
- return 1;
-
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-
- val.i[0] = CONST_DOUBLE_LOW (c);
- val.i[1] = CONST_DOUBLE_HIGH (c);
-
- for (i = 0; i < 7; i ++)
- if (val.d == 1 << i || val.d == 1 / (1 << i))
- return 1;
-#endif
- return 0;
-}
-
-
-/* Return the cost in cycles of a memory address, relative to register
- indirect.
-
- Each of the following adds the indicated number of cycles:
-
- 1 - symbolic address
- 1 - pre-decrement
- 1 - indexing and/or offset(register)
- 2 - indirect */
-
-
-int vax_address_cost(addr)
- register rtx addr;
-{
- int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0;
- rtx plus_op0 = 0, plus_op1 = 0;
- restart:
- switch (GET_CODE (addr))
- {
- case PRE_DEC:
- predec = 1;
- case REG:
- case SUBREG:
- case POST_INC:
- reg = 1;
- break;
- case MULT:
- indexed = 1; /* 2 on VAX 2 */
- break;
- case CONST_INT:
- /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */
- if (offset == 0)
- offset = (unsigned)(INTVAL(addr)+128) > 256;
- break;
- case CONST:
- case SYMBOL_REF:
- offset = 1; /* 2 on VAX 2 */
- break;
- case LABEL_REF: /* this is probably a byte offset from the pc */
- if (offset == 0)
- offset = 1;
- break;
- case PLUS:
- if (plus_op0)
- plus_op1 = XEXP (addr, 0);
- else
- plus_op0 = XEXP (addr, 0);
- addr = XEXP (addr, 1);
- goto restart;
- case MEM:
- indir = 2; /* 3 on VAX 2 */
- addr = XEXP (addr, 0);
- goto restart;
- }
-
- /* Up to 3 things can be added in an address. They are stored in
- plus_op0, plus_op1, and addr. */
-
- if (plus_op0)
- {
- addr = plus_op0;
- plus_op0 = 0;
- goto restart;
- }
- if (plus_op1)
- {
- addr = plus_op1;
- plus_op1 = 0;
- goto restart;
- }
- /* Indexing and register+offset can both be used (except on a VAX 2)
- without increasing execution time over either one alone. */
- if (reg && indexed && offset)
- return reg + indir + offset + predec;
- return reg + indexed + indir + offset + predec;
-}
-
-
-/* Cost of an expression on a VAX. This version has costs tuned for the
- CVAX chip (found in the VAX 3 series) with comments for variations on
- other models. */
-
-int
-vax_rtx_cost (x)
- register rtx x;
-{
- register enum rtx_code code = GET_CODE (x);
- enum machine_mode mode = GET_MODE (x);
- register int c;
- int i = 0; /* may be modified in switch */
- char *fmt = GET_RTX_FORMAT (code); /* may be modified in switch */
-
- switch (code)
- {
- case POST_INC:
- return 2;
- case PRE_DEC:
- return 3;
- case MULT:
- switch (mode)
- {
- case DFmode:
- c = 16; /* 4 on VAX 9000 */
- break;
- case SFmode:
- c = 9; /* 4 on VAX 9000, 12 on VAX 2 */
- break;
- case DImode:
- c = 16; /* 6 on VAX 9000, 28 on VAX 2 */
- break;
- case SImode:
- case HImode:
- case QImode:
- c = 10; /* 3-4 on VAX 9000, 20-28 on VAX 2 */
- break;
- }
- break;
- case UDIV:
- c = 17;
- break;
- case DIV:
- if (mode == DImode)
- c = 30; /* highly variable */
- else if (mode == DFmode)
- /* divide takes 28 cycles if the result is not zero, 13 otherwise */
- c = 24;
- else
- c = 11; /* 25 on VAX 2 */
- break;
- case MOD:
- c = 23;
- break;
- case UMOD:
- c = 29;
- break;
- case FLOAT:
- c = 6 + (mode == DFmode) + (GET_MODE (XEXP (x, 0)) != SImode);
- /* 4 on VAX 9000 */
- break;
- case FIX:
- c = 7; /* 17 on VAX 2 */
- break;
- case ASHIFT:
- case LSHIFTRT:
- case ASHIFTRT:
- if (mode == DImode)
- c = 12;
- else
- c = 10; /* 6 on VAX 9000 */
- break;
- case ROTATE:
- case ROTATERT:
- c = 6; /* 5 on VAX 2, 4 on VAX 9000 */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- fmt = "e"; /* all constant rotate counts are short */
- break;
- case PLUS:
- /* Check for small negative integer operand: subl2 can be used with
- a short positive constant instead. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- if ((unsigned)(INTVAL (XEXP (x, 1)) + 63) < 127)
- fmt = "e";
- case MINUS:
- c = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */
- case IOR:
- case XOR:
- c = 3;
- break;
- case AND:
- /* AND is special because the first operand is complemented. */
- c = 3;
- if (GET_CODE (XEXP (x, 0)) == CONST_INT)
- {
- if ((unsigned)~INTVAL (XEXP (x, 0)) > 63)
- c = 4;
- fmt = "e";
- i = 1;
- }
- break;
- case NEG:
- if (mode == DFmode)
- return 9;
- else if (mode == SFmode)
- return 6;
- else if (mode == DImode)
- return 4;
- case NOT:
- return 2;
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- c = 15;
- break;
- case MEM:
- if (mode == DImode || mode == DFmode)
- c = 5; /* 7 on VAX 2 */
- else
- c = 3; /* 4 on VAX 2 */
- x = XEXP (x, 0);
- if (GET_CODE (x) == REG || GET_CODE (x) == POST_INC)
- return c;
- return c + vax_address_cost (x);
- default:
- c = 3;
- break;
- }
-
-
- /* Now look inside the expression. Operands which are not registers or
- short constants add to the cost.
-
- FMT and I may have been adjusted in the switch above for instructions
- which require special handling */
-
- while (*fmt++ == 'e')
- {
- register rtx op = XEXP (x, i++);
- code = GET_CODE (op);
-
- /* A NOT is likely to be found as the first operand of an AND
- (in which case the relevant cost is of the operand inside
- the not) and not likely to be found anywhere else. */
- if (code == NOT)
- op = XEXP (op, 0), code = GET_CODE (op);
-
- switch (code)
- {
- case CONST_INT:
- if ((unsigned)INTVAL (op) > 63 && GET_MODE (x) != QImode)
- c += 1; /* 2 on VAX 2 */
- break;
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- c += 1; /* 2 on VAX 2 */
- break;
- case CONST_DOUBLE:
- if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
- {
- /* Registers are faster than floating point constants -- even
- those constants which can be encoded in a single byte. */
- if (vax_float_literal (op))
- c++;
- else
- c += (GET_MODE (x) == DFmode) ? 3 : 2;
- }
- else
- {
- if (CONST_DOUBLE_HIGH (op) != 0
- || (unsigned)CONST_DOUBLE_LOW (op) > 63)
- c += 2;
- }
- break;
- case MEM:
- c += 1; /* 2 on VAX 2 */
- if (GET_CODE (XEXP (op, 0)) != REG)
- c += vax_address_cost (XEXP (op, 0));
- break;
- case REG:
- case SUBREG:
- break;
- default:
- c += 1;
- break;
- }
- }
- return c;
-}
-
-/* Check a `double' value for validity for a particular machine mode. */
-
-static char *float_strings[] =
-{
- "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
- "-1.70141173319264430e+38",
- "2.93873587705571877e-39", /* 2^-128 */
- "-2.93873587705571877e-39"
-};
-
-static REAL_VALUE_TYPE float_values[4];
-
-static int inited_float_values = 0;
-
-
-int
-check_float_value (mode, d, overflow)
- enum machine_mode mode;
- REAL_VALUE_TYPE *d;
- int overflow;
-{
- if (inited_float_values == 0)
- {
- int i;
- for (i = 0; i < 4; i++)
- {
- float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode);
- }
-
- inited_float_values = 1;
- }
-
- if (overflow)
- {
- bcopy ((char *) &float_values[0], (char *) d, sizeof (REAL_VALUE_TYPE));
- return 1;
- }
-
- if ((mode) == SFmode)
- {
- REAL_VALUE_TYPE r;
- bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE));
- if (REAL_VALUES_LESS (float_values[0], r))
- {
- bcopy ((char *) &float_values[0], (char *) d,
- sizeof (REAL_VALUE_TYPE));
- return 1;
- }
- else if (REAL_VALUES_LESS (r, float_values[1]))
- {
- bcopy ((char *) &float_values[1], (char*) d,
- sizeof (REAL_VALUE_TYPE));
- return 1;
- }
- else if (REAL_VALUES_LESS (dconst0, r)
- && REAL_VALUES_LESS (r, float_values[2]))
- {
- bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
- return 1;
- }
- else if (REAL_VALUES_LESS (r, dconst0)
- && REAL_VALUES_LESS (float_values[3], r))
- {
- bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
- return 1;
- }
- }
-
- return 0;
-}
-
-#ifdef VMS_TARGET
-/* Additional support code for VMS target. */
-
-/* Linked list of all externals that are to be emitted when optimizing
- for the global pointer if they haven't been declared by the end of
- the program with an appropriate .comm or initialization. */
-
-static
-struct extern_list {
- struct extern_list *next; /* next external */
- char *name; /* name of the external */
- int size; /* external's actual size */
- int in_const; /* section type flag */
-} *extern_head = 0, *pending_head = 0;
-
-/* Check whether NAME is already on the external definition list. If not,
- add it to either that list or the pending definition list. */
-
-void
-vms_check_external (decl, name, pending)
- tree decl;
- char *name;
- int pending;
-{
- register struct extern_list *p, *p0;
-
- for (p = extern_head; p; p = p->next)
- if (!strcmp (p->name, name))
- return;
-
- for (p = pending_head, p0 = 0; p; p0 = p, p = p->next)
- if (!strcmp (p->name, name))
- {
- if (pending)
- return;
-
- /* Was pending, but has now been defined; move it to other list. */
- if (p == pending_head)
- pending_head = p->next;
- else
- p0->next = p->next;
- p->next = extern_head;
- extern_head = p;
- return;
- }
-
- /* Not previously seen; create a new list entry. */
- p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list));
- p->name = name;
-
- if (pending)
- {
- /* Save the size and section type and link to `pending' list. */
- p->size = (DECL_SIZE (decl) == 0) ? 0 :
- TREE_INT_CST_LOW (size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
- size_int (BITS_PER_UNIT)));
- p->in_const = (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl));
-
- p->next = pending_head;
- pending_head = p;
- }
- else
- {
- /* Size and section type don't matter; link to `declared' list. */
- p->size = p->in_const = 0; /* arbitrary init */
-
- p->next = extern_head;
- extern_head = p;
- }
- return;
-}
-
-void
-vms_flush_pending_externals (file)
- FILE *file;
-{
- register struct extern_list *p;
-
- while (pending_head)
- {
- /* Move next pending declaration to the "done" list. */
- p = pending_head;
- pending_head = p->next;
- p->next = extern_head;
- extern_head = p;
-
- /* Now output the actual declaration. */
- if (p->in_const)
- const_section ();
- else
- data_section ();
- fputs (".comm ", file);
- assemble_name (file, p->name);
- fprintf (file, ",%d\n", p->size);
- }
-}
-#endif /* VMS_TARGET */
-
-#ifdef VMS
-/* Additional support code for VMS host. */
-
-#ifdef QSORT_WORKAROUND
- /*
- Do not use VAXCRTL's qsort() due to a severe bug: once you've
- sorted something which has a size that's an exact multiple of 4
- and is longword aligned, you cannot safely sort anything which
- is either not a multiple of 4 in size or not longword aligned.
- A static "move-by-longword" optimization flag inside qsort() is
- never reset. This is known of affect VMS V4.6 through VMS V5.5-1,
- and was finally fixed in VMS V5.5-2.
-
- In this work-around an insertion sort is used for simplicity.
- The qsort code from glibc should probably be used instead.
- */
-void
-not_qsort (array, count, size, compare)
- void *array;
- unsigned count, size;
- int (*compare)();
-{
-
- if (size == sizeof (short))
- {
- register int i;
- register short *next, *prev;
- short tmp, *base = array;
-
- for (next = base, i = count - 1; i > 0; i--)
- {
- prev = next++;
- if ((*compare)(next, prev) < 0)
- {
- tmp = *next;
- do *(prev + 1) = *prev;
- while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
- *(prev + 1) = tmp;
- }
- }
- }
- else if (size == sizeof (long))
- {
- register int i;
- register long *next, *prev;
- long tmp, *base = array;
-
- for (next = base, i = count - 1; i > 0; i--)
- {
- prev = next++;
- if ((*compare)(next, prev) < 0)
- {
- tmp = *next;
- do *(prev + 1) = *prev;
- while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0);
- *(prev + 1) = tmp;
- }
- }
- }
- else /* arbitrary size */
- {
- register int i;
- register char *next, *prev, *tmp = alloca (size), *base = array;
-
- for (next = base, i = count - 1; i > 0; i--)
- { /* count-1 forward iterations */
- prev = next, next += size; /* increment front pointer */
- if ((*compare)(next, prev) < 0)
- { /* found element out of order; move others up then re-insert */
- memcpy (tmp, next, size); /* save smaller element */
- do { memcpy (prev + size, prev, size); /* move larger elem. up */
- prev -= size; /* decrement back pointer */
- } while (prev >= base ? (*compare)(tmp, prev) < 0 : 0);
- memcpy (prev + size, tmp, size); /* restore small element */
- }
- }
-#ifdef USE_C_ALLOCA
- alloca (0);
-#endif
- }
-
- return;
-}
-#endif /* QSORT_WORKAROUND */
-
-#endif /* VMS */