diff options
Diffstat (limited to 'gcc/config/vax/vax.c')
-rwxr-xr-x | gcc/config/vax/vax.c | 837 |
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 */ |