home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
config
/
alpha.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
41KB
|
1,517 lines
/* Subroutines used for code generation on the DEC Alpha.
Copyright (C) 1992 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@nyu.edu)
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "config.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"
#include "recog.h"
#include "reload.h"
#include "expr.h"
#include "obstack.h"
#include "tree.h"
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
rtx alpha_compare_op0, alpha_compare_op1;
int alpha_compare_fp_p;
/* Save the name of the current function as used by the assembler. This
is used by the epilogue. */
char *alpha_function_name;
/* Nonzero if the current function needs gp. */
int alpha_function_needs_gp;
/* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */
int
zap_mask (value)
HOST_WIDE_INT value;
{
int i;
for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
i++, value >>= 8)
if ((value & 0xff) != 0 && (value & 0xff) != 0xff)
return 0;
return 1;
}
/* Returns 1 if OP is either the constant zero or a register. If a
register, it must be in the proper mode unless MODE is VOIDmode. */
int
reg_or_0_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return op == const0_rtx || register_operand (op, mode);
}
/* Return 1 if OP is an 8-bit constant or any register. */
int
reg_or_8bit_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
|| register_operand (op, mode));
}
/* Return 1 if the operand is a valid second operand to an add insn. */
int
add_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000
|| ((INTVAL (op) & 0xffff) == 0
&& (INTVAL (op) >> 31 == -1
|| INTVAL (op) >> 31 == 0)));
return register_operand (op, mode);
}
/* Return 1 if the operand is a valid second operand to a sign-extending
add insn. */
int
sext_add_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255
|| (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255);
return register_operand (op, mode);
}
/* Return 1 if OP is the constant 4 or 8. */
int
const48_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 4 || INTVAL (op) == 8));
}
/* Return 1 if OP is a valid first operand to an AND insn. */
int
and_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
return (zap_mask (CONST_DOUBLE_LOW (op))
&& zap_mask (CONST_DOUBLE_HIGH (op)));
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
|| zap_mask (INTVAL (op)));
return register_operand (op, mode);
}
/* Return 1 if OP is a constant that is the width, in bits, of an integral
mode smaller than DImode. */
int
mode_width_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32));
}
/* Return 1 if OP is a constant that is the width of an integral machine mode
smaller than an integer. */
int
mode_mask_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
#if HOST_BITS_PER_WIDE_INT == 32
if (GET_CODE (op) == CONST_DOUBLE)
return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1;
#endif
if (GET_CODE (op) == CONST_INT)
return (INTVAL (op) == 0xff
|| INTVAL (op) == 0xffff
#if HOST_BITS_PER_WIDE_INT == 64
|| INTVAL (op) == 0xffffffff
#endif
);
}
/* Return 1 if OP is a multiple of 8 less than 64. */
int
mul8_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 64
&& (INTVAL (op) & 7) == 0);
}
/* Return 1 if OP is the constant zero in floating-point. */
int
fp0_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return (GET_MODE (op) == mode
&& GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode));
}
/* Return 1 if OP is the floating-point constant zero or a register. */
int
reg_or_fp0_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return fp0_operand (op, mode) || register_operand (op, mode);
}
/* Return 1 if OP is a register or a constant integer. */
int
reg_or_cint_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == CONST_INT || register_operand (op, mode);
}
/* Return 1 if OP is a valid operand for the source of a move insn. */
int
input_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode)
return 0;
switch (GET_CODE (op))
{
case LABEL_REF:
case SYMBOL_REF:
case CONST:
return mode == DImode;
case REG:
return 1;
case SUBREG:
if (register_operand (op, mode))
return 1;
/* ... fall through ... */
case MEM:
return mode != HImode && mode != QImode && general_operand (op, mode);
case CONST_DOUBLE:
return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
case CONST_INT:
return mode == QImode || mode == HImode || add_operand (op, mode);
}
return 0;
}
/* Return 1 if OP is a SYMBOL_REF for the current function. */
int
current_function_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == SYMBOL_REF
&& ! strcmp (XSTR (op, 0), current_function_name));
}
/* Return 1 if OP is a valid Alpha comparison operator. Here we know which
comparisons are valid in which insn. */
int
alpha_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
enum rtx_code code = GET_CODE (op);
if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
return 0;
return (code == EQ || code == LE || code == LT
|| (mode == DImode && (code == LEU || code == LTU)));
}
/* Return 1 if OP is a signed comparison operation. */
int
signed_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
switch (GET_CODE (op))
{
case EQ: case NE: case LE: case LT: case GE: case GT:
return 1;
}
return 0;
}
/* Return 1 if this is a divide or modulus operator. */
int
divmod_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
switch (GET_CODE (op))
{
case DIV: case MOD: case UDIV: case UMOD:
return 1;
}
return 0;
}
/* Return 1 if this memory address is a known aligned register plus
a constant. It must be a valid address. This means that we can do
this as an aligned reference plus some offset.
Take into account what reload will do.
We could say that out-of-range stack slots are alignable, but that would
complicate get_aligned_mem a