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
/
i960.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
56KB
|
2,246 lines
/* Subroutines used for code generation on intel 80960.
Copyright (C) 1992 Free Software Foundation, Inc.
Contributed by Steven McGeady, Intel Corp.
Additional Work by Glenn Colon-Bonet, Jonathan Shapiro, Andy Wilson
Converted to GCC 2.0 by Jim Wilson and Michael Tiemann, Cygnus Support.
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 "tree.h"
#include "insn-codes.h"
#include "assert.h"
#include "expr.h"
#include "function.h"
#include "recog.h"
#include <math.h>
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
rtx i960_compare_op0, i960_compare_op1;
/* Used to implement #pragma align/noalign. Initialized by OVERRIDE_OPTIONS
macro in i960.h. */
static int i960_maxbitalignment;
static int i960_last_maxbitalignment;
/* Used to implement switching between MEM and ALU insn types, for better
C series performance. */
enum insn_types i960_last_insn_type;
/* The leaf-procedure return register. Set only if this is a leaf routine. */
static int i960_leaf_ret_reg;
/* True if replacing tail calls with jumps is OK. */
static int tail_call_ok;
/* A string containing a list of insns to emit in the epilogue so as to
restore all registers saved by the prologue. Created by the prologue
code as it saves registers away. */
char epilogue_string[1000];
/* A unique number (per function) for return labels. */
static int ret_label = 0;
#if 0
/* Handle pragmas for compatibility with Intel's compilers. */
/* ??? This is incomplete, since it does not handle all pragmas that the
intel compilers understand. Also, it needs to be rewritten to accept
a stream instead of a string for GCC 2. */
void
process_pragma(str)
char *str;
{
int align;
int i;
if ((i = sscanf (str, " align %d", &align)) == 1)
switch (align)
{
case 0: /* Return to last alignment. */
align = i960_last_maxbitalignment / 8;
case 16: /* Byte alignments. */
case 8:
case 4:
case 2:
case 1:
i960_last_maxbitalignment = i960_maxbitalignment;
i960_maxbitalignment = align * 8;
break;
default: /* Unknown, silently ignore. */
break;
}
/* NOTE: ic960 R3.0 pragma align definition:
#pragma align [(size)] | (identifier=size[,...])
#pragma noalign [(identifier)[,...]]
(all parens are optional)
- size is [1,2,4,8,16]
- noalign means size==1
- applies only to component elements of a struct (and union?)
- identifier applies to structure tag (only)
- missing identifier means next struct
- alignment rules for bitfields need more investigation */
/* Should be pragma 'far' or equivalent for callx/balx here. */
}
#endif
/* Initialize variables before compiling any files. */
void
i960_initialize ()
{
if (TARGET_IC_COMPAT2_0)
{
i960_maxbitalignment = 8;
i960_last_maxbitalignment = 128;
}
else
{
i960_maxbitalignment = 128;
i960_last_maxbitalignment = 8;
}
}
/* Return true if OP can be used as the source of an fp move insn. */
int
fpmove_src_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == CONST_DOUBLE || general_operand (op, mode));
}
#if 0
/* Return true if OP is a register or zero. */
int
reg_or_zero_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return register_operand (op, mode) || op == const0_rtx;
}
#endif
/* Return truth value of whether OP can be used as an operands in a three
address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */
int
arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode) || literal (op, mode));
}
/* Return true if OP is a register or a valid floating point literal. */
int
fp_arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode) || fp_literal (op, mode));
}
/* Return true is OP is a register or a valid signed integer literal. */
int
signed_arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode) || signed_literal (op, mode));
}
/* Return truth value of whether OP is a integer which fits the
range constraining immediate operands in three-address insns. */
int
literal (op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_CODE (op) == CONST_INT) && INTVAL(op) >= 0 && INTVAL(op) < 32);
}
/* Return true if OP is a float constant of 1. */
int
fp_literal_one (op, mode)
rtx op;
enum machine_mode mode;
{
return (TARGET_NUMERICS && (mode == VOIDmode || mode == GET_MODE (op))
&& (op == CONST1_RTX (mode)));
}
/* Return true if OP is a float constant of 0. */
int
fp_literal_zero (op, mode)
rtx op;
enum machine_mode mode;
{
return (TARGET_NUMERICS && (mode == VOIDmode || mode == GET_MODE (op))
&& (op == CONST0_RTX (mode)));
}
/* Return true if OP is a valid floating point literal. */
int
fp_literal(op, mode)
rtx op;
enum machine_mode mode;
{
return fp_literal_zero (op, mode) || fp_literal_one (op, mode);
}
/* Return true if OP is a valid signed immediate constant. */
int
signed_literal(op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_CODE (op) == CONST_INT) && INTVAL(op) > -32 && INTVAL(op) < 32);
}
/* Return truth value of statement that OP is a symbolic memory
operand of mode MODE. */
int
symbolic_memory_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
}
/* Return truth value of whether OP is EQ or NE. */
int
eq_or_neq (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
}
/* OP is an integer register or a constant. */
int
arith32_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
return 1;
return (CONSTANT_P (op));
}
/* Return true if OP is an integer constant which is a power of 2. */
int
power2_operand (op,mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE(op) != CONST_INT)
return 0;
return exact_log2 (INTVAL (op)) >= 0;
}
/* If VAL has only one bit set, return the index of that bit. Otherwise
return -1. */
int
bitpos (val)
unsigned int val;
{
register int i;
for (i = 0; val != 0; i++, val >>= 1)
{
if (val & 1)
{
if (val != 1)
return -1;
return i;
}
}
return -1;
}
/* Return non-zero if OP is a mask, i.e. all one bits are consecutive.
The return value indicates how many consecutive non-zero bits exist
if this is a mask. This is the same as the next function, except that
it does not indicate what the start and stop bit positions are. */
int
is_mask (val)
unsigned int val;
{
register int start, end, i;
start = -1;
for (i = 0; val != 0; val >>= 1, i++)
{
if (val & 1)
{
if (start < 0)
start = i;
end = i;
continue;
}
/* Still looking for the first bit. */
if (start < 0)
continue