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
/
a29k.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
38KB
|
1,434 lines
/* Subroutines used for code generation on AMD Am29000.
Copyright (C) 1987, 1988, 1990, 1991, 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 "expr.h"
#include "obstack.h"
#include "tree.h"
#include "reload.h"
#define min(A,B) ((A) < (B) ? (A) : (B))
/* This gives the size in words of the register stack for the current
procedure. */
static int a29k_regstack_size;
/* This points to the last insn of the insn prologue. It is set when
an insn without a filled delay slot is found near the start of the
function. */
static char *a29k_last_prologue_insn;
/* This points to the first insn that will be in the epilogue. It is null if
no epilogue is required. */
static char *a29k_first_epilogue_insn;
/* This is nonzero if a a29k_first_epilogue_insn was put in a delay slot. It
indicates that an intermediate label needs to be written. */
static int a29k_first_epilogue_insn_used;
/* Location to hold the name of the current function. We need this prolog to
contain the tag words prior to the declaration. So the name must be stored
away. */
char *a29k_function_name;
/* Mapping of registers to debug register numbers. The only change is
for the frame pointer and the register numbers used for the incoming
arguments. */
int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
rtx a29k_compare_op0, a29k_compare_op1;
int a29k_compare_fp_p;
/* Gives names for registers. */
extern char *reg_names[];
/* Returns 1 if OP is a 8-bit constant. */
int
cint_8_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;
}
/* Returns 1 if OP is a 16-bit constant. */
int
cint_16_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;
}
/* Returns 1 if OP is a constant that cannot be moved in a single insn. */
int
long_const_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (! CONSTANT_P (op))
return 0;
if (TARGET_29050 && GET_CODE (op) == CONST_INT
&& (INTVAL (op) & 0xffff) == 0)
return 0;
return (GET_CODE (op) != CONST_INT
|| ((INTVAL (op) & 0xffff0000) != 0
&& (INTVAL (op) & 0xffff0000) != 0xffff0000
&& INTVAL (op) != 0x80000000));
}
/* The following four functions detect constants of 0, 8, 16, and 24 used as
a position in ZERO_EXTRACT operations. They can either be the appropriate
constant integer or a shift (which will be produced by combine). */
static int
shift_constant_operand (op, mode, val)
rtx op;
enum machine_mode mode;
int val;
{
return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val)
|| (GET_CODE (op) == ASHIFT
&& GET_CODE (XEXP (op, 0)) == CONST_INT
&& INTVAL (XEXP (op, 0)) == val / 8
&& GET_CODE (XEXP (op, 1)) == CONST_INT
&& INTVAL (XEXP (op, 1)) == 3));
}
int
const_0_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 0);
}
int
const_8_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 8);
}
int
const_16_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 16);
}
int
const_24_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return shift_constant_operand (op, mode, 24);
}
/* Returns 1 if OP is a floating-point constant of the proper mode. */
int
float_const_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;
}
/* Returns 1 if OP is a floating-point constant of the proper mode or a
general-purpose register. */
int
gpc_reg_or_float_constant_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return float_const_operand (op, mode) || gpc_reg_operand (op, mode);
}
/* Returns 1 if OP is an integer constant of the proper mode or a
general-purpose register. */
int
gpc_reg_or_integer_constant_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_MODE (op) == VOIDmode
&& (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
|| gpc_reg_operand (op, mode));
}
/* Returns 1 if OP is a special machine register. */
int
spec_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != REG || GET_MODE (op) != mode)
return 0;
switch (GET_MODE_CLASS (mode))
{
case MODE_PARTIAL_INT:
return REGNO (op) >= R_BP && REGNO (op) <= R_CR;
case MODE_INT:
return REGNO (op) >= R_Q && REGNO (op) <= R_EXO;
detault:
return 0;
}
}
/* Returns 1 if OP is an accumulator register. */
int
accum_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == REG
&& REGNO (op) >= R_ACC (0) && REGNO (op) <= R_ACC (3));
}
/* Returns 1 if OP is a normal data register. */
int
gpc_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
if (GET_CODE (op) == REG)
regno = REGNO (op);
else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
{
regno = REGNO (SUBREG_REG (op));
if (regno < FIRST_PSEUDO_REGISTER)
regno += SUBREG_WORD (op);
}
else
return 0;
return regno >= FIRST_PSEUDO_REGISTER || regno < R_BP;
}
/* Returns 1 if OP is either an 8-bit constant integer or a general register.
If a register, it must be in the proper mode unless MODE is VOIDmode. */
int
srcb_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == CONST_INT
&& (mode == QImode
|| (INTVAL (op) & 0xffffff00) == 0))
return 1;
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
return gpc_reg_operand (op, mode);
}
/* Return 1 if OP is either an immediate or a general register. This is used
for the input operand of mtsr/mtrsim. */
int
gpc_reg_or_immediate_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return gpc_reg_operand (op, mode) || immediate_operand (op, mode);
}
/* Return 1 if OP can be used as the second operand of and AND insn. This
includes srcb_operand and a constant whose complement fits in 8 bits. */
int
and_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (srcb_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
&& ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
}
/* Return 1 if OP can be used as the second operand of an ADD insn.
This is the same as above, except we use negative, rather than
complement. */
int
add_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (srcb_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
&& ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));
}
/* Return 1 if OP is a valid address in a CALL_INSN. These are a SYMBOL_REF
to the current function, all SYMBOL_REFs if TARGET_SMALL_MEMORY, or
a sufficiently-smal