Bulk ns32k patch from Ian Dall. See ChangeLog for details.
Co-Authored-By: Matthias Pfaller <leo@dachau.marco.de> From-SVN: r23887
This commit is contained in:
parent
36696297f1
commit
8357595779
102
gcc/ChangeLog
102
gcc/ChangeLog
@ -1,3 +1,102 @@
|
||||
Wed Nov 25 23:32:02 1998 Ian Dall <Ian.Dall@dsto.defence.gov.au>
|
||||
Matthias Pfaller <leo@dachau.marco.de>
|
||||
|
||||
* invoke.texi (Option Summary, NS32K Options): add description
|
||||
of NS32K specific options.
|
||||
|
||||
* ns32k.md (tstdf, cmpdf, movdf, truncdfsf2, fixdfqi2, fixdfhi2,
|
||||
fixdfsi2, fixunsdfqi2, fixunsdfhi2, fixunsdfsi2, fix_truncdfqi2,
|
||||
fix_truncdfhi2, fix_truncdfsi2, adddf3, subdf3, muldf3, divdf3,
|
||||
negdf2, absdf2): Use l instead of f since the double class and
|
||||
float class are no longer the same.
|
||||
(cmpsi, truncsiqi2, truncsihi2, addsi3, subsi3, mulsi3, umulsidi3,
|
||||
divsi3, modsi3, andsi3, iorsi3, xorsi3, negsi2, one_cmplsi2,
|
||||
ashlsi3, ashlhi3, ashlqi3, rotlsi3, rotlhi3, rotlqi3, abssi2,...):
|
||||
use "g" instead of "rmn" since LEGITIMATE_PIC_OPERAND has been
|
||||
fixed.
|
||||
(cmpsi, cmphi, cmpqi): use general_operand instead of
|
||||
non_immediate_operand. Removes erroneous assumption that can't
|
||||
compare constants.
|
||||
(movsf, movsi, movhi, movqi,...): New register numbering scheme.
|
||||
(movsi, addsi3): Use NS32K_DISPLACEMENT_P instead of hard coded
|
||||
constants.
|
||||
(movstrsi, movstrsi1, movstrsi2): completely new block move
|
||||
scheme.
|
||||
(...): Patterns to exploit multiply-add instructions.
|
||||
(udivmodsi4, udivmodsi_internal4, udivmodhi4,
|
||||
udivmoddihi4_internal, udivmodqi4, udivmoddiqi4_internal): new
|
||||
patterns to exploit extended divide insns.
|
||||
(udivsi3, udivhi3, udivqi3): remove since superceded by udivmodsi
|
||||
etc patterns.
|
||||
|
||||
* ns32k.h (FUNCTION_VALUE, LIBCALL_VALUE): Use f0 for complex
|
||||
float return values as well as simple scalar floats.
|
||||
(TARGET_32381, TARGET_MULT_ADD, TARGET_SWITCHES):
|
||||
support new flag to denote 32381 fpu.
|
||||
(OVERRIDE_OPTIONS): 32381 is a strict superset of 32081.
|
||||
(CONDITIONAL_REGISTER_USAGE): disable extra 32381 registers if not
|
||||
compling for 32381.
|
||||
(FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS,
|
||||
REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES, OUTPUT_REGISTER_NAMES,
|
||||
REG_ALLOC_ORDER, DBX_REGISTER_NUMBER, R0_REGNUM, F0_REGNUM,
|
||||
L1_REGNUM, STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM,
|
||||
LONG_FP_REGS_P, ARG_POINTER_REGNUM, reg_class, REG_CLASS_NAMES,
|
||||
REG_CLASS_CONTENTS, SUBSET_P,REGNO_REG_CLASS,
|
||||
REG_CLASS_FROM_LETTER, FUNCTION_PROLOGUE, FUNCTION_EPILOGUE,
|
||||
REGNO_OK_FOR_INDEX_P, FP_REG_P, REG_OK_FOR_INDEX_P,
|
||||
REG_OK_FOR_BASE_P, MEM_REG): new register scheme to include 32381
|
||||
fpu registers and special register classes for new 32381
|
||||
instructions dotf and polyf.
|
||||
(MODES_TIEABLE_P): Allow all integer modes, notably DI and SI, to
|
||||
be tieable.
|
||||
(INCOMING_RETURN_ADDR_RTX, RETURN_ADDR_RTX,
|
||||
INCOMING_FRAME_SP_OFFSET): New macros in case DWARF support is
|
||||
required.
|
||||
(SMALL_REGISTER_CLASSES): Make dependant on -mmult-add option.
|
||||
(MOVE_RATIO): Set to zero because of smart movstrsi implimentation.
|
||||
(REGISTER_MOVE_COST): move code to register_move_cost function for
|
||||
ease of coding and debugging.
|
||||
(CLASS_LIKELY_SPILLED_P): Under new register scheme class
|
||||
LONG_FLOAT_REGO is likely spilled but not caught by default
|
||||
definition.
|
||||
(CONSTANT_ADDRESS_P, CONSTANT_ADDRESS_NO_LABEL_P): use macro
|
||||
instead of hard coded numbers in range check.
|
||||
(ASM_OUTPUT_LABELREF_AS_INT): delete since unused.
|
||||
(...): Add prototypes for functions in ns32k.c but disable because
|
||||
of problems when ns32k.h is included in machine independant files.
|
||||
|
||||
* ns32k.c: include "system.h", "tree.h", "expr.h", "flags.h".
|
||||
(ns32k_reg_class_contents, regcass_map, ns32k_out_reg_names,
|
||||
hard_regno_mode_ok, secondary_reload_class,
|
||||
print_operand, print_operand_address): new register scheme to
|
||||
include 32381 fpu registers and special register classes for new
|
||||
32381 instructions dotf and polyf.
|
||||
(gen_indexed_expr): Make static to keep namespace clean.
|
||||
(check_reg): remove since never called.
|
||||
(move_tail, expand_block_move): helper functions for "movstrsi"
|
||||
block move insn.
|
||||
(register_move_cost): Helper function for REGISTER_MOVE_COST macro.
|
||||
Increase cost of moves which go via memory.
|
||||
* netbsd.h (TARGET_DEFAULT): Set (new) 32381 fpu flag.
|
||||
(CPP_PREDEFINES): nolonger predefine "unix".
|
||||
|
||||
* ns32k.md (movsi, movsi, adddi3, subdi3, subsi3, subhi3, subqi3,...):
|
||||
Remove erroneous %$. print_operand() can work out from the rtx is
|
||||
an immediate prefix is required.
|
||||
|
||||
* ns32k.h (RETURN_POPS_ARGS, VALID_MACHINE_DECL_ATTRIBUTE,
|
||||
VALID_MACHINE_TYPE_ATTRIBUTE, COMP_TYPE_ATTRIBUTES,
|
||||
SET_DEFAULT_TYPE_ATTRIBUTES): Support for -mrtd calling
|
||||
convention.
|
||||
(LEGITIMATE_PIC_OPERAND_P, SYMBOLIC_CONST): Correct handling of
|
||||
pic operands.
|
||||
|
||||
* ns32k.c (symbolic_reference_mentioned_p, print_operand):
|
||||
Correct handling of pic operands.
|
||||
(ns32k_valid_decl_attribute_p, ns32k_valid_type_attribute_p,
|
||||
ns32k_comp_type_attributes, ns32k_return_pops_args): Support for
|
||||
-mrtd calling convention.
|
||||
|
||||
Wed Nov 25 23:42:20 1998 Tom Tromey <tromey@cygnus.com>
|
||||
|
||||
* gcc.c (option_map): Recognize --output-class-directory.
|
||||
@ -13,7 +112,6 @@ Thu Nov 26 18:26:21 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
too large to be immediate constants. Also use it to find terms
|
||||
common to initial and final iteration values that can be removed.
|
||||
|
||||
|
||||
Thu Nov 26 18:05:04 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* loop.h (struct loop_info): Define new structure.
|
||||
@ -42,7 +140,6 @@ Thu Nov 26 18:05:04 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
(loop_unroll_factor): Replace global array by element in
|
||||
loop_info structure.
|
||||
|
||||
|
||||
Thu Nov 26 17:49:29 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* loop.c (check_dbra_loop): Update JUMP_LABEL field of jump insn
|
||||
@ -87,7 +184,6 @@ Thu Nov 26 15:16:05 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
(valid_parallel_operands_4, valid_parallel_operands_5,
|
||||
valid_parallel_operands_6): Reject pattern if the register destination
|
||||
of the first set is used as part of an address in the second set.
|
||||
|
||||
|
||||
Thu Nov 26 14:56:32 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
|
@ -1,6 +1,55 @@
|
||||
This file describes the implementation notes of the GNU C Compiler for
|
||||
the National Semiconductor 32032 chip (and 32000 family).
|
||||
|
||||
Much of this file was obsolete. It described restrictions caused by
|
||||
bugs in early versions of of the ns32032 chip and by bugs in sequent
|
||||
assemblers and linkers of the time.
|
||||
|
||||
Many (all?) of the chip bugs were fixed in later revisions and
|
||||
certainly fixed by later chips in the same series (ns32332 and
|
||||
ns32532).
|
||||
|
||||
Conditional code to support sequent assembler and/or linker restrictions
|
||||
has not been removed deliberately, but has probably not been tested in
|
||||
a *very* long time.
|
||||
|
||||
Support for one sequent assembler bug has *not* been retained.
|
||||
It was necessary to say:
|
||||
|
||||
addr _x,rn
|
||||
cmpd _p,rn
|
||||
|
||||
rather than:
|
||||
|
||||
cmpd _p,@_x
|
||||
|
||||
|
||||
This used to be forced by the use of "rmn" register constraints rather
|
||||
than "g". This is bad for other platforms which do not have this
|
||||
restraint.
|
||||
|
||||
It is likely that there are no Balance 8000's still in operation, but
|
||||
if there are and the assembler bug was never fixed then the easiest
|
||||
way to run gcc would be to also run gas.
|
||||
|
||||
The code required by the sequent assembler is still generated when the
|
||||
-fpic flag is in effect and this is forced by the appropriate
|
||||
definition of LEGITIMATE_PIC_OPERAND_P. If support for the old sequent
|
||||
assembler bug is required, then this could be achieved by adding the
|
||||
test from LEGITIMATE_PIC_OPERAND to the GO_IF_LEGITIMATE_ADDRESS
|
||||
definition. Of course, this should be conditional on something in the
|
||||
sequent.h config file.
|
||||
|
||||
The original contents of this file appear below as an historical note.
|
||||
SEQUENT_ADDRESS_BUG mentioned below has been replaced by
|
||||
INDEX_RATHER_THAN_BASE. Note that merlin.h still defines
|
||||
SEQUENT_ADDRESS_BUG even though it is not used anywhere. Since it has
|
||||
been like this for a long time, presumably either the
|
||||
SEQUENT_ADDRESS_BUG is not required for the merlin, or no one is using
|
||||
gcc on the merlin anymore.
|
||||
|
||||
HISTORICAL NOTE
|
||||
|
||||
The 32032 machine description and configuration file for this compiler
|
||||
is, for NS32000 family machine, primarily machine independent.
|
||||
However, since this release still depends on vendor-supplied
|
||||
|
@ -24,9 +24,10 @@ Boston, MA 02111-1307, USA.
|
||||
|
||||
/* Compile for the floating point unit & 32532 by default;
|
||||
Don't assume SB is zero;
|
||||
Don't use bitfield instructions; */
|
||||
Don't use bitfield instructions;
|
||||
FPU is 32381; */
|
||||
|
||||
#define TARGET_DEFAULT (1 + 24 + 32 + 64)
|
||||
#define TARGET_DEFAULT (1 + 24 + 32 + 64 + 256)
|
||||
|
||||
/* 32-bit alignment for efficiency */
|
||||
|
||||
@ -68,7 +69,7 @@ Boston, MA 02111-1307, USA.
|
||||
/* Names to predefine in the preprocessor for this target machine. */
|
||||
|
||||
#undef CPP_PREDEFINES
|
||||
#define CPP_PREDEFINES "-Dunix -Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)"
|
||||
#define CPP_PREDEFINES "-Dns32k -Dns32000 -Dns32532 -D__NetBSD__ -Dpc532 -D__ns32k__ -D__KPRINTF_ATTRIBUTE__ -Asystem(unix) -Asystem(NetBSD) -Acpu(ns32k) -Amachine(ns32k)"
|
||||
|
||||
/* Make gcc agree with <machine/ansi.h> */
|
||||
|
||||
|
@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Some output-actions in ns32k.md need these. */
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include "system.h"
|
||||
#include "rtl.h"
|
||||
#include "regs.h"
|
||||
#include "hard-reg-set.h"
|
||||
@ -30,11 +30,33 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "insn-flags.h"
|
||||
#include "output.h"
|
||||
#include "insn-attr.h"
|
||||
#include "tree.h"
|
||||
#include "expr.h"
|
||||
#include "flags.h"
|
||||
|
||||
#ifdef OSF_OS
|
||||
int ns32k_num_files = 0;
|
||||
#endif
|
||||
|
||||
/* This duplicates reg_class_contens in reg_class.c, but maybe that isn't
|
||||
initialized in time. Also this is more convenient as an array of ints.
|
||||
We know that HARD_REG_SET fits in an unsigned int */
|
||||
|
||||
unsigned int ns32k_reg_class_contents[N_REG_CLASSES] = REG_CLASS_CONTENTS;
|
||||
|
||||
enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
|
||||
{
|
||||
GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
|
||||
GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
|
||||
FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS, FLOAT_REGS,
|
||||
FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
|
||||
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
||||
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
||||
FRAME_POINTER_REG, STACK_POINTER_REG
|
||||
};
|
||||
|
||||
char *ns32k_out_reg_names[] = OUTPUT_REGISTER_NAMES;
|
||||
|
||||
void
|
||||
trace (s, s1, s2)
|
||||
char *s, *s1, *s2;
|
||||
@ -42,78 +64,67 @@ trace (s, s1, s2)
|
||||
fprintf (stderr, s, s1, s2);
|
||||
}
|
||||
|
||||
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
|
||||
|
||||
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
|
||||
int
|
||||
hard_regno_mode_ok (regno, mode)
|
||||
int regno;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
switch (mode)
|
||||
int size = GET_MODE_UNIT_SIZE(mode);
|
||||
|
||||
if (FLOAT_MODE_P(mode))
|
||||
{
|
||||
case QImode:
|
||||
case HImode:
|
||||
case PSImode:
|
||||
case SImode:
|
||||
case PDImode:
|
||||
case VOIDmode:
|
||||
case BLKmode:
|
||||
if (regno < 8 || regno == 16 || regno == 17)
|
||||
if (size == UNITS_PER_WORD && regno < L1_REGNUM)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
case DImode:
|
||||
if (regno < 8 && (regno & 1) == 0)
|
||||
if (size == UNITS_PER_WORD * 2
|
||||
&& (((regno & 1) == 0 && regno < FRAME_POINTER_REGNUM)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
case SFmode:
|
||||
case SCmode:
|
||||
if (TARGET_32081)
|
||||
{
|
||||
if (regno < 16)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regno < 8)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
case DFmode:
|
||||
case DCmode:
|
||||
if ((regno & 1) == 0)
|
||||
{
|
||||
if (TARGET_32081)
|
||||
{
|
||||
if (regno < 16)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regno < 8)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Used to abort here, but simply saying "no" handles TImode
|
||||
much better. */
|
||||
if (size == UNITS_PER_WORD * 2
|
||||
&& (regno & 1) == 0 && regno < F0_REGNUM)
|
||||
return 1;
|
||||
if (size <= UNITS_PER_WORD
|
||||
&& (regno < F0_REGNUM || regno == FRAME_POINTER_REGNUM
|
||||
|| regno == STACK_POINTER_REGNUM))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_move_cost(CLASS1, CLASS2)
|
||||
enum reg_class CLASS1;
|
||||
enum reg_class CLASS2;
|
||||
{
|
||||
if (CLASS1 == NO_REGS || CLASS2 == NO_REGS)
|
||||
return 2;
|
||||
if((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
|
||||
|| (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)))
|
||||
return 8;
|
||||
if (((CLASS1) == STACK_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
|
||||
|| ((CLASS2) == STACK_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
|
||||
return 6;
|
||||
if (((CLASS1) == FRAME_POINTER_REG && !SUBSET_P(CLASS2,GENERAL_REGS))
|
||||
|| ((CLASS2) == FRAME_POINTER_REG && !SUBSET_P(CLASS1,GENERAL_REGS)))
|
||||
return 6;
|
||||
return 2;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* We made the insn definitions copy from floating point to general
|
||||
registers via the stack. */
|
||||
int secondary_memory_needed(CLASS1, CLASS2, M)
|
||||
enum reg_class CLASS1;
|
||||
enum reg_class CLASS2;
|
||||
enum machine_mode M;
|
||||
{
|
||||
int ret = ((SUBSET_P(CLASS1, FP_REGS) && !SUBSET_P(CLASS2, FP_REGS))
|
||||
|| (!SUBSET_P(CLASS1, FP_REGS) && SUBSET_P(CLASS2, FP_REGS)));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* ADDRESS_COST calls this. This function is not optimal
|
||||
for the 32032 & 32332, but it probably is better than
|
||||
the default. */
|
||||
@ -146,8 +157,10 @@ calc_address_cost (operand)
|
||||
case POST_DEC:
|
||||
case PRE_DEC:
|
||||
break;
|
||||
case MULT:
|
||||
case MEM:
|
||||
cost += calc_address_cost (XEXP (operand, 0));
|
||||
break;
|
||||
case MULT:
|
||||
case PLUS:
|
||||
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
|
||||
{
|
||||
@ -174,30 +187,18 @@ secondary_reload_class (class, mode, in)
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
regno = -1;
|
||||
|
||||
/* We can place anything into GENERAL_REGS and can put GENERAL_REGS
|
||||
into anything. */
|
||||
if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
|
||||
if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
|
||||
|| ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
|
||||
return GENERAL_REGS;
|
||||
else
|
||||
return NO_REGS;
|
||||
|
||||
/* Constants, memory, and FP registers can go into FP registers. */
|
||||
if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
|
||||
return NO_REGS;
|
||||
|
||||
#if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
|
||||
so it's cleaner to use PREFERRED_RELOAD_CLASS
|
||||
to make the right things happen. */
|
||||
if (regno >= 16 && class == GEN_AND_MEM_REGS)
|
||||
return NO_REGS;
|
||||
#endif
|
||||
|
||||
/* Otherwise, we need GENERAL_REGS. */
|
||||
return GENERAL_REGS;
|
||||
}
|
||||
|
||||
/* Generate the rtx that comes from an address expression in the md file */
|
||||
/* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
|
||||
scale must be converted from an exponent (from ASHIFT) to a
|
||||
multiplier (for MULT). */
|
||||
rtx
|
||||
static rtx
|
||||
gen_indexed_expr (base, index, scale)
|
||||
rtx base, index, scale;
|
||||
{
|
||||
@ -226,6 +227,7 @@ reg_or_mem_operand (op, mode)
|
||||
|| GET_CODE (op) == SUBREG
|
||||
|| GET_CODE (op) == MEM));
|
||||
}
|
||||
|
||||
|
||||
/* Split one or more DImode RTL references into pairs of SImode
|
||||
references. The RTL can be REG, offsettable MEM, integer constant, or
|
||||
@ -404,28 +406,164 @@ output_move_double (operands)
|
||||
return singlemove_string (operands);
|
||||
}
|
||||
|
||||
int
|
||||
check_reg (oper, reg)
|
||||
rtx oper;
|
||||
int reg;
|
||||
{
|
||||
register int i;
|
||||
|
||||
#define MAX_UNALIGNED_COPY (32)
|
||||
/* Expand string/block move operations.
|
||||
|
||||
if (oper == 0)
|
||||
return 0;
|
||||
switch (GET_CODE(oper))
|
||||
operands[0] is the pointer to the destination.
|
||||
operands[1] is the pointer to the source.
|
||||
operands[2] is the number of bytes to move.
|
||||
operands[3] is the alignment. */
|
||||
|
||||
static void
|
||||
move_tail(operands, bytes, offset)
|
||||
rtx operands[];
|
||||
int bytes;
|
||||
int offset;
|
||||
{
|
||||
if (bytes & 2)
|
||||
{
|
||||
case REG:
|
||||
return (REGNO(oper) == reg) ? 1 : 0;
|
||||
case MEM:
|
||||
return check_reg(XEXP(oper, 0), reg);
|
||||
case PLUS:
|
||||
case MULT:
|
||||
return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
|
||||
rtx src, dest;
|
||||
dest = change_address(operands[0], HImode,
|
||||
plus_constant(XEXP(operands[0], 0), offset));
|
||||
src = change_address(operands[1], HImode,
|
||||
plus_constant(XEXP(operands[1], 0), offset));
|
||||
emit_move_insn(dest, src);
|
||||
offset += 2;
|
||||
}
|
||||
if (bytes & 1)
|
||||
{
|
||||
rtx src, dest;
|
||||
dest = change_address(operands[0], QImode,
|
||||
plus_constant(XEXP(operands[0], 0), offset));
|
||||
src = change_address(operands[1], QImode,
|
||||
plus_constant(XEXP(operands[1], 0), offset));
|
||||
emit_move_insn(dest, src);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
expand_block_move (operands)
|
||||
rtx operands[];
|
||||
{
|
||||
rtx bytes_rtx = operands[2];
|
||||
rtx align_rtx = operands[3];
|
||||
int constp = (GET_CODE (bytes_rtx) == CONST_INT);
|
||||
int bytes = (constp ? INTVAL (bytes_rtx) : 0);
|
||||
int align = INTVAL (align_rtx);
|
||||
rtx src_reg = gen_rtx(REG, Pmode, 1);
|
||||
rtx dest_reg = gen_rtx(REG, Pmode, 2);
|
||||
rtx count_reg = gen_rtx(REG, SImode, 0);
|
||||
rtx insn;
|
||||
|
||||
if (constp && bytes <= 0)
|
||||
return;
|
||||
|
||||
if (constp && bytes < 20)
|
||||
{
|
||||
int words = bytes >> 2;
|
||||
if (words)
|
||||
if (words < 3 || flag_unroll_loops)
|
||||
{
|
||||
int offset = 0;
|
||||
for (; words; words--, offset += 4)
|
||||
{
|
||||
rtx src, dest;
|
||||
dest = change_address(operands[0], SImode,
|
||||
plus_constant(XEXP(operands[0], 0), offset));
|
||||
src = change_address(operands[1], SImode,
|
||||
plus_constant(XEXP(operands[1], 0), offset));
|
||||
emit_move_insn(dest, src);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use movmd. It is slower than multiple movd's but more
|
||||
compact. It is also slower than movsd for large copies
|
||||
but causes less registers reloading so is better than movsd
|
||||
for small copies. */
|
||||
rtx src, dest;
|
||||
dest = copy_addr_to_reg (XEXP(operands[0], 0));
|
||||
src = copy_addr_to_reg (XEXP(operands[1], 0));
|
||||
|
||||
emit_insn(gen_movstrsi2(dest, src, GEN_INT(words)));
|
||||
}
|
||||
move_tail(operands, bytes & 3, bytes & ~3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (align > UNITS_PER_WORD)
|
||||
align = UNITS_PER_WORD;
|
||||
|
||||
/* Move the address into scratch registers. */
|
||||
emit_insn(gen_rtx(CLOBBER, VOIDmode, dest_reg));
|
||||
emit_move_insn(dest_reg, XEXP (operands[0], 0));
|
||||
emit_insn(gen_rtx(CLOBBER, VOIDmode, src_reg));
|
||||
emit_move_insn(src_reg, XEXP (operands[1], 0));
|
||||
emit_insn(gen_rtx(CLOBBER, VOIDmode, count_reg));
|
||||
|
||||
if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY))
|
||||
{
|
||||
rtx bytes_reg;
|
||||
|
||||
/* constant no of bytes and aligned or small enough copy to not bother
|
||||
* aligning. Emit insns to copy by words.
|
||||
*/
|
||||
if (bytes >> 2)
|
||||
{
|
||||
emit_move_insn(count_reg, GEN_INT(bytes >> 2));
|
||||
emit_insn(gen_movstrsi1 (GEN_INT(4)));
|
||||
}
|
||||
/* insns to copy rest */
|
||||
move_tail(operands, bytes & 3, bytes & ~3);
|
||||
}
|
||||
else if (align == UNITS_PER_WORD)
|
||||
{
|
||||
/* insns to copy by words */
|
||||
emit_insn(gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT(2)));
|
||||
emit_insn(gen_movstrsi1 (GEN_INT(4)));
|
||||
/* insns to copy rest */
|
||||
emit_insn(gen_andsi3 (count_reg, bytes_rtx, GEN_INT(3)));
|
||||
emit_insn(gen_movstrsi1 (const1_rtx));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not aligned and we may have a lot to copy so it is worth
|
||||
* aligning.
|
||||
*/
|
||||
rtx aligned_label = gen_label_rtx ();
|
||||
rtx bytes_reg;
|
||||
|
||||
bytes_reg = copy_to_mode_reg(SImode, bytes_rtx);
|
||||
if (!constp)
|
||||
{
|
||||
/* Emit insns to test and skip over the alignment if it is
|
||||
* not worth it. This doubles as a test to ensure that the alignment
|
||||
* operation can't copy too many bytes
|
||||
*/
|
||||
emit_insn(gen_cmpsi (bytes_reg, GEN_INT(MAX_UNALIGNED_COPY)));
|
||||
emit_jump_insn (gen_blt (aligned_label));
|
||||
}
|
||||
|
||||
/* Emit insns to do alignment at run time */
|
||||
emit_insn(gen_negsi2 (count_reg, src_reg));
|
||||
emit_insn(gen_andsi3 (count_reg, count_reg, GEN_INT(3)));
|
||||
emit_insn(gen_subsi3 (bytes_reg, bytes_reg, count_reg));
|
||||
emit_insn(gen_movstrsi1 (const1_rtx));
|
||||
if (!constp)
|
||||
emit_label (aligned_label);
|
||||
|
||||
/* insns to copy by words */
|
||||
emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT(2)));
|
||||
emit_insn(gen_movstrsi1 (GEN_INT(4)));
|
||||
|
||||
/* insns to copy rest */
|
||||
emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT(3)));
|
||||
emit_insn(gen_movstrsi1 (const1_rtx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if OP contains a global symbol reference */
|
||||
|
||||
int
|
||||
@ -465,11 +603,143 @@ global_symbolic_reference_mentioned_p (op, f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if OP contains a symbol reference */
|
||||
|
||||
int
|
||||
symbolic_reference_mentioned_p (op)
|
||||
rtx op;
|
||||
{
|
||||
register char *fmt;
|
||||
register int i;
|
||||
|
||||
if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
|
||||
return 1;
|
||||
|
||||
fmt = GET_RTX_FORMAT (GET_CODE (op));
|
||||
for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'E')
|
||||
{
|
||||
register int j;
|
||||
|
||||
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
|
||||
if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
|
||||
return 1;
|
||||
}
|
||||
else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
|
||||
attribute for DECL. The attributes in ATTRIBUTES have previously been
|
||||
assigned to DECL. */
|
||||
|
||||
int
|
||||
ns32k_valid_decl_attribute_p (decl, attributes, identifier, args)
|
||||
tree decl;
|
||||
tree attributes;
|
||||
tree identifier;
|
||||
tree args;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
|
||||
attribute for TYPE. The attributes in ATTRIBUTES have previously been
|
||||
assigned to TYPE. */
|
||||
|
||||
int
|
||||
ns32k_valid_type_attribute_p (type, attributes, identifier, args)
|
||||
tree type;
|
||||
tree attributes;
|
||||
tree identifier;
|
||||
tree args;
|
||||
{
|
||||
if (TREE_CODE (type) != FUNCTION_TYPE
|
||||
&& TREE_CODE (type) != FIELD_DECL
|
||||
&& TREE_CODE (type) != TYPE_DECL)
|
||||
return 0;
|
||||
|
||||
/* Stdcall attribute says callee is responsible for popping arguments
|
||||
if they are not variable. */
|
||||
if (is_attribute_p ("stdcall", identifier))
|
||||
return (args == NULL_TREE);
|
||||
|
||||
/* Cdecl attribute says the callee is a normal C declaration */
|
||||
if (is_attribute_p ("cdecl", identifier))
|
||||
return (args == NULL_TREE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 if the attributes for two types are incompatible, 1 if they
|
||||
are compatible, and 2 if they are nearly compatible (which causes a
|
||||
warning to be generated). */
|
||||
|
||||
int
|
||||
ns32k_comp_type_attributes (type1, type2)
|
||||
tree type1;
|
||||
tree type2;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Value is the number of bytes of arguments automatically
|
||||
popped when returning from a subroutine call.
|
||||
FUNDECL is the declaration node of the function (as a tree),
|
||||
FUNTYPE is the data type of the function (as a tree),
|
||||
or for a library call it is an identifier node for the subroutine name.
|
||||
SIZE is the number of bytes of arguments passed on the stack.
|
||||
|
||||
On the ns32k, the RET insn may be used to pop them if the number
|
||||
of args is fixed, but if the number is variable then the caller
|
||||
must pop them all. RET can't be used for library calls now
|
||||
because the library is compiled with the Unix compiler.
|
||||
Use of RET is a selectable option, since it is incompatible with
|
||||
standard Unix calling sequences. If the option is not selected,
|
||||
the caller must always pop the args.
|
||||
|
||||
The attribute stdcall is equivalent to RET on a per module basis. */
|
||||
|
||||
int
|
||||
ns32k_return_pops_args (fundecl, funtype, size)
|
||||
tree fundecl;
|
||||
tree funtype;
|
||||
int size;
|
||||
{
|
||||
int rtd = TARGET_RTD;
|
||||
|
||||
if (TREE_CODE (funtype) == IDENTIFIER_NODE)
|
||||
return rtd ? size : 0;
|
||||
|
||||
/* Cdecl functions override -mrtd, and never pop the stack */
|
||||
if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
|
||||
return 0;
|
||||
|
||||
/* Stdcall functions will pop the stack if not variable args */
|
||||
if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
|
||||
rtd = 1;
|
||||
|
||||
if (rtd)
|
||||
{
|
||||
if (TYPE_ARG_TYPES (funtype) == NULL_TREE
|
||||
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PRINT_OPERAND is defined to call this function,
|
||||
which is easier to debug than putting all the code in
|
||||
a macro definition in ns32k.h. */
|
||||
|
||||
/* XXX time 12% of cpu time is in fprintf for non optimizing */
|
||||
void
|
||||
print_operand (file, x, code)
|
||||
FILE *file;
|
||||
@ -481,7 +751,7 @@ print_operand (file, x, code)
|
||||
else if (code == '?')
|
||||
PUT_EXTERNAL_PREFIX (file);
|
||||
else if (GET_CODE (x) == REG)
|
||||
fprintf (file, "%s", reg_names[REGNO (x)]);
|
||||
fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]);
|
||||
else if (GET_CODE (x) == MEM)
|
||||
{
|
||||
rtx tmp = XEXP (x, 0);
|
||||
@ -528,11 +798,30 @@ print_operand (file, x, code)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flag_pic
|
||||
&& GET_CODE (x) == CONST
|
||||
&& symbolic_reference_mentioned_p (x))
|
||||
{
|
||||
fprintf(stderr, "illegal constant for pic-mode: \n");
|
||||
print_rtl(stderr, x);
|
||||
fprintf(stderr, "\nGET_CODE (x) == %d, CONST == %d, symbolic_reference_mentioned_p (x) == %d\n",
|
||||
GET_CODE (x), CONST, symbolic_reference_mentioned_p(x));
|
||||
abort ();
|
||||
}
|
||||
else if (flag_pic
|
||||
&& (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
|
||||
{
|
||||
output_addr_const (file, x);
|
||||
fprintf (file, "(sb)");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
#endif
|
||||
PUT_IMMEDIATE_PREFIX (file);
|
||||
output_addr_const (file, x);
|
||||
PUT_IMMEDIATE_PREFIX (file);
|
||||
output_addr_const (file, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,6 +834,7 @@ print_operand (file, x, code)
|
||||
figure out how it worked.
|
||||
90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
|
||||
|
||||
void
|
||||
print_operand_address (file, addr)
|
||||
register FILE *file;
|
||||
register rtx addr;
|
||||
@ -597,7 +887,7 @@ print_operand_address (file, addr)
|
||||
base = tmp;
|
||||
break;
|
||||
case REG:
|
||||
if (REGNO (tmp) < 8)
|
||||
if (REGNO (tmp) < F0_REGNUM)
|
||||
if (base)
|
||||
{
|
||||
indexexp = tmp;
|
||||
@ -728,7 +1018,7 @@ print_operand_address (file, addr)
|
||||
(disp(sb)) (MEM ...)
|
||||
*/
|
||||
case REG:
|
||||
fprintf (file, "(%s)", reg_names[REGNO (base)]);
|
||||
fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
|
||||
break;
|
||||
case SYMBOL_REF:
|
||||
if (! flag_pic)
|
||||
@ -785,7 +1075,7 @@ print_operand_address (file, addr)
|
||||
fprintf (file, "(");
|
||||
output_addr_const (file, offset);
|
||||
if (base)
|
||||
fprintf (file, "(%s)", reg_names[REGNO (base)]);
|
||||
fprintf (file, "(%s)", ns32k_out_reg_names[REGNO (base)]);
|
||||
else if (TARGET_SB)
|
||||
fprintf (file, "(sb)");
|
||||
else
|
||||
@ -816,16 +1106,16 @@ print_operand_address (file, addr)
|
||||
}
|
||||
else
|
||||
scale = 0;
|
||||
if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
|
||||
if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= F0_REGNUM)
|
||||
abort ();
|
||||
|
||||
#ifdef UTEK_ASM
|
||||
fprintf (file, "[%c`%s]",
|
||||
scales[scale],
|
||||
reg_names[REGNO (indexexp)]);
|
||||
ns32k_out_reg_names[REGNO (indexexp)]);
|
||||
#else
|
||||
fprintf (file, "[%s:%c]",
|
||||
reg_names[REGNO (indexexp)],
|
||||
ns32k_out_reg_names[REGNO (indexexp)],
|
||||
scales[scale]);
|
||||
#endif
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ Boston, MA 02111-1307, USA. */
|
||||
/* Note that some other tm.h files include this one and then override
|
||||
many of the definitions that relate to assembler syntax. */
|
||||
|
||||
extern enum reg_class secondary_reload_class();
|
||||
|
||||
/* Names to predefine in the preprocessor for this target machine. */
|
||||
|
||||
#define CPP_PREDEFINES "-Dns32000 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)"
|
||||
@ -66,6 +64,18 @@ extern int target_flags;
|
||||
|
||||
/* Compile 32081 insns for floating point (not library calls). */
|
||||
#define TARGET_32081 (target_flags & 1)
|
||||
#define TARGET_32381 (target_flags & 256)
|
||||
|
||||
/* The use of multiply-add instructions is optional because it can
|
||||
* cause an abort due to being unable to find a spill register. The
|
||||
* main problem is that the multiply-add instructions require f0 and
|
||||
* f0 is not available for spilling because it is "explicitly
|
||||
* mentioned" in the rtl for function return values. This can be fixed
|
||||
* by defining SMALL_REGISTER_CLASSES, but that causes worse code for
|
||||
* the (more common) integer case. We really need better reload code.
|
||||
*/
|
||||
|
||||
#define TARGET_MULT_ADD (target_flags & 512)
|
||||
|
||||
/* Compile using rtd insn calling sequence.
|
||||
This will not work unless you use prototypes at least
|
||||
@ -93,9 +103,9 @@ extern int target_flags;
|
||||
where VALUE is the bits to set or minus the bits to clear.
|
||||
An empty string NAME is used to identify the default VALUE. */
|
||||
|
||||
#define TARGET_SWITCHES \
|
||||
#define TARGET_SWITCHES \
|
||||
{ { "32081", 1}, \
|
||||
{ "soft-float", -1}, \
|
||||
{ "soft-float", -257}, \
|
||||
{ "rtd", 2}, \
|
||||
{ "nortd", -2}, \
|
||||
{ "regparm", 4}, \
|
||||
@ -110,17 +120,66 @@ extern int target_flags;
|
||||
{ "nobitfield", 64}, \
|
||||
{ "himem", 128}, \
|
||||
{ "nohimem", -128}, \
|
||||
{ "32381", 256}, \
|
||||
{ "mult-add", 512}, \
|
||||
{ "nomult-add", -512}, \
|
||||
{ "", TARGET_DEFAULT}}
|
||||
|
||||
/* TARGET_DEFAULT is defined in encore.h, pc532.h, etc. */
|
||||
|
||||
/* When we are generating PIC, the sb is used as a pointer
|
||||
to the GOT. */
|
||||
to the GOT. 32381 is a superset of 32081 */
|
||||
|
||||
#define OVERRIDE_OPTIONS \
|
||||
{ \
|
||||
#define OVERRIDE_OPTIONS \
|
||||
{ \
|
||||
if (flag_pic || TARGET_HIMEM) target_flags |= 32; \
|
||||
if (TARGET_32381) target_flags |= 1; \
|
||||
else target_flags &= ~512; \
|
||||
}
|
||||
|
||||
/* Zero or more C statements that may conditionally modify two
|
||||
variables `fixed_regs' and `call_used_regs' (both of type `char
|
||||
[]') after they have been initialized from the two preceding
|
||||
macros.
|
||||
|
||||
This is necessary in case the fixed or call-clobbered registers
|
||||
depend on target flags.
|
||||
|
||||
You need not define this macro if it has no work to do.
|
||||
|
||||
If the usage of an entire class of registers depends on the target
|
||||
flags, you may indicate this to GCC by using this macro to modify
|
||||
`fixed_regs' and `call_used_regs' to 1 for each of the registers in
|
||||
the classes which should not be used by GCC. Also define the macro
|
||||
`REG_CLASS_FROM_LETTER' to return `NO_REGS' if it is called with a
|
||||
letter for a class that shouldn't be used.
|
||||
|
||||
(However, if this class is not included in `GENERAL_REGS' and all
|
||||
of the insn patterns whose constraints permit this class are
|
||||
controlled by target switches, then GCC will automatically avoid
|
||||
using these registers when the target switches are opposed to
|
||||
them.) */
|
||||
|
||||
#define CONDITIONAL_REGISTER_USAGE \
|
||||
do \
|
||||
{ \
|
||||
if (!TARGET_32081) \
|
||||
{ \
|
||||
int regno; \
|
||||
\
|
||||
for (regno = F0_REGNUM; regno <= F0_REGNUM + 8; regno++) \
|
||||
fixed_regs[regno] = call_used_regs[regno] = 1; \
|
||||
} \
|
||||
if (!TARGET_32381) \
|
||||
{ \
|
||||
int regno; \
|
||||
\
|
||||
for (regno = L1_REGNUM; regno <= L1_REGNUM + 8; regno++) \
|
||||
fixed_regs[regno] = call_used_regs[regno] = 1; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
/* target machine storage layout */
|
||||
|
||||
@ -190,13 +249,14 @@ extern int target_flags;
|
||||
from 0 to just below FIRST_PSEUDO_REGISTER.
|
||||
All registers that the compiler knows about must be given numbers,
|
||||
even those that are not normally considered general registers. */
|
||||
#define FIRST_PSEUDO_REGISTER 18
|
||||
#define FIRST_PSEUDO_REGISTER 26
|
||||
|
||||
/* 1 for registers that have pervasive standard uses
|
||||
and are not available for the register allocator.
|
||||
On the ns32k, these are the FP, SP, (SB and PC are not included here). */
|
||||
#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, \
|
||||
1, 1}
|
||||
|
||||
/* 1 for registers not available across function calls.
|
||||
@ -207,13 +267,70 @@ extern int target_flags;
|
||||
Aside from that, you can include as many other registers as you like. */
|
||||
#define CALL_USED_REGISTERS {1, 1, 1, 0, 0, 0, 0, 0, \
|
||||
1, 1, 1, 1, 0, 0, 0, 0, \
|
||||
1, 1, 0, 0, 0, 0, 0, 0, \
|
||||
1, 1}
|
||||
|
||||
/* How to refer to registers in assembler output.
|
||||
This sequence is indexed by compiler's hard-register-number (see above). */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
|
||||
"l1", "l1h","l3", "l3h","l5", "l5h","l7", "l7h", \
|
||||
"fp", "sp"}
|
||||
|
||||
|
||||
#define ADDITIONAL_REGISTER_NAMES \
|
||||
{{"l0", 8}, {"l2", 10}, {"l4", 12}, {"l6", 14}}
|
||||
|
||||
/* l0-7 are not recognized by the assembler. These are the names to use,
|
||||
* but we don't want ambiguous names in REGISTER_NAMES
|
||||
*/
|
||||
#define OUTPUT_REGISTER_NAMES \
|
||||
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
|
||||
"f1", "l1h","f3", "l3h","f5", "l5h","f7", "f7h", \
|
||||
"fp", "sp"}
|
||||
|
||||
#define REG_ALLOC_ORDER \
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 10, 11, 18, 12, 13, 20, 14, 15, 22, 24, 25, 17, 19, 23}
|
||||
|
||||
/* How to renumber registers for dbx and gdb.
|
||||
NS32000 may need more change in the numeration. XXX */
|
||||
|
||||
#define DBX_REGISTER_NUMBER(REGNO) \
|
||||
((REGNO) < L1_REGNUM? (REGNO) \
|
||||
: (REGNO) < FRAME_POINTER_REGNUM? (REGNO) - L1_REGNUM + 22 \
|
||||
: (REGNO) == FRAME_POINTER_REGNUM? 17 \
|
||||
: 16)
|
||||
|
||||
|
||||
|
||||
|
||||
#define R0_REGNUM 0
|
||||
#define F0_REGNUM 8
|
||||
#define L1_REGNUM 16
|
||||
|
||||
/* Specify the registers used for certain standard purposes.
|
||||
The values of these macros are register numbers. */
|
||||
|
||||
/* NS32000 pc is not overloaded on a register. */
|
||||
/* #define PC_REGNUM */
|
||||
|
||||
/* Register to use for pushing function arguments. */
|
||||
#define STACK_POINTER_REGNUM 25
|
||||
|
||||
/* Base register for access to local variables of the function. */
|
||||
#define FRAME_POINTER_REGNUM 24
|
||||
|
||||
|
||||
/* Return number of consecutive hard regs needed starting at reg REGNO
|
||||
to hold something of mode MODE.
|
||||
This is ordinarily the length in words of a value of mode MODE
|
||||
but can be less for certain modes in special long registers.
|
||||
On the ns32k, all registers are 32 bits long. */
|
||||
On the ns32k, all registers are 32 bits long except for the 32381 "long"
|
||||
registers but we treat those as pairs */
|
||||
#define LONG_FP_REGS_P(REGNO) ((REGNO) >= L1_REGNUM && (REGNO) < L1_REGNUM + 8)
|
||||
#define HARD_REGNO_NREGS(REGNO, MODE) \
|
||||
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
||||
|
||||
@ -223,22 +340,19 @@ extern int target_flags;
|
||||
/* Value is 1 if it is a good idea to tie two pseudo registers
|
||||
when one has mode MODE1 and one has mode MODE2.
|
||||
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
|
||||
for any hard reg, then this must be 0 for correct output. */
|
||||
#define MODES_TIEABLE_P(MODE1, MODE2) \
|
||||
(((MODE1) == DFmode || (MODE1) == DCmode || (MODE1) == DImode) == \
|
||||
((MODE2) == DFmode || (MODE2) == DCmode || (MODE2) == DImode))
|
||||
for any hard reg, then this must be 0 for correct output.
|
||||
|
||||
/* Specify the registers used for certain standard purposes.
|
||||
The values of these macros are register numbers. */
|
||||
Early documentation says SI and DI are not tieable if some reg can
|
||||
be OK for SI but not for DI. However other ports (mips, i860, mvs
|
||||
and tahoe) don't meet the above criterion. Evidently the real
|
||||
requirement is somewhat laxer. Documentation was changed for gcc
|
||||
2.8 but was not picked up by egcs (at least egcs 1.0). Having all
|
||||
integer modes tieable definitely generates faster code. */
|
||||
|
||||
/* NS32000 pc is not overloaded on a register. */
|
||||
/* #define PC_REGNUM */
|
||||
|
||||
/* Register to use for pushing function arguments. */
|
||||
#define STACK_POINTER_REGNUM 17
|
||||
|
||||
/* Base register for access to local variables of the function. */
|
||||
#define FRAME_POINTER_REGNUM 16
|
||||
#define MODES_TIEABLE_P(MODE1, MODE2) \
|
||||
((FLOAT_MODE_P(MODE1) && FLOAT_MODE_P(MODE2) \
|
||||
&& (GET_MODE_UNIT_SIZE(MODE1) == GET_MODE_UNIT_SIZE(MODE2))) \
|
||||
|| (!FLOAT_MODE_P(MODE1) && !FLOAT_MODE_P(MODE2)))
|
||||
|
||||
/* Value should be nonzero if functions must have frame pointers.
|
||||
Zero means the frame pointer need not be set up (and parms
|
||||
@ -247,7 +361,7 @@ extern int target_flags;
|
||||
#define FRAME_POINTER_REQUIRED 0
|
||||
|
||||
/* Base register for access to arguments of the function. */
|
||||
#define ARG_POINTER_REGNUM 16
|
||||
#define ARG_POINTER_REGNUM 24
|
||||
|
||||
/* Register in which static-chain is passed to a function. */
|
||||
#define STATIC_CHAIN_REGNUM 1
|
||||
@ -275,37 +389,39 @@ extern int target_flags;
|
||||
|
||||
For any two classes, it is very desirable that there be another
|
||||
class that represents their union. */
|
||||
|
||||
enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
FRAME_POINTER_REG, STACK_POINTER_REG,
|
||||
GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES };
|
||||
|
||||
enum reg_class
|
||||
{ NO_REGS, GENERAL_REGS, FLOAT_REG0, LONG_FLOAT_REG0, FLOAT_REGS,
|
||||
FP_REGS, GEN_AND_FP_REGS, FRAME_POINTER_REG, STACK_POINTER_REG,
|
||||
GEN_AND_MEM_REGS, ALL_REGS, LIM_REG_CLASSES };
|
||||
|
||||
#define N_REG_CLASSES (int) LIM_REG_CLASSES
|
||||
|
||||
/* Give names of register classes as strings for dump file. */
|
||||
|
||||
#define REG_CLASS_NAMES \
|
||||
{"NO_REGS", "GENERAL_REGS", "FLOAT_REGS", "GEN_AND_FP_REGS", \
|
||||
"FRAME_POINTER_REG", "STACK_POINTER_REG", "GEN_AND_MEM_REGS", "ALL_REGS" }
|
||||
{"NO_REGS", "GENERAL_REGS", "FLOAT_REG0", "LONG_FLOAT_REG0", "FLOAT_REGS", \
|
||||
"FP_REGS", "GEN_AND_FP_REGS", "FRAME_POINTER_REG", "STACK_POINTER_REG", \
|
||||
"GEN_AND_MEM_REGS", "ALL_REGS" }
|
||||
|
||||
/* Define which registers fit in which classes.
|
||||
This is an initializer for a vector of HARD_REG_SET
|
||||
of length N_REG_CLASSES. */
|
||||
|
||||
#define REG_CLASS_CONTENTS {0, 0x00ff, 0xff00, 0xffff, \
|
||||
0x10000, 0x20000, 0x300ff, 0x3ffff }
|
||||
#define REG_CLASS_CONTENTS {0, 0x00ff, 0x100, 0x300, 0xff00, \
|
||||
0xffff00, 0xffffff, 0x1000000, 0x2000000, \
|
||||
0x30000ff, 0x3ffffff }
|
||||
|
||||
#define SUBSET_P(CLASS1, CLASS2) \
|
||||
((ns32k_reg_class_contents[CLASS1] & ~ns32k_reg_class_contents[CLASS2]) \
|
||||
== 0)
|
||||
|
||||
/* The same information, inverted:
|
||||
Return the class number of the smallest class containing
|
||||
reg number REGNO. This could be a conditional expression
|
||||
or could index an array. */
|
||||
|
||||
#define REGNO_REG_CLASS(REGNO) \
|
||||
((REGNO) < 8 ? GENERAL_REGS \
|
||||
: (REGNO) < 16 ? FLOAT_REGS \
|
||||
: (REGNO) == 16 ? FRAME_POINTER_REG \
|
||||
: (REGNO) == 17 ? STACK_POINTER_REG \
|
||||
: NO_REGS)
|
||||
#define REGNO_REG_CLASS(REGNO) (regclass_map[REGNO])
|
||||
|
||||
/* The class value for index registers, and the one for base regs. */
|
||||
|
||||
@ -314,10 +430,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
|
||||
/* Get reg_class from a letter such as appears in the machine description. */
|
||||
|
||||
#define REG_CLASS_FROM_LETTER(C) \
|
||||
((C) == 'f' ? FLOAT_REGS \
|
||||
: (C) == 'x' ? FRAME_POINTER_REG \
|
||||
: (C) == 'y' ? STACK_POINTER_REG \
|
||||
#define REG_CLASS_FROM_LETTER(C) \
|
||||
((C) == 'u' ? FLOAT_REG0 \
|
||||
: (C) == 'v' ? LONG_FLOAT_REG0 \
|
||||
: (C) == 'f' ? FLOAT_REGS \
|
||||
: (C) == 'l' ? FP_REGS \
|
||||
: (C) == 'x' ? FRAME_POINTER_REG \
|
||||
: (C) == 'y' ? STACK_POINTER_REG \
|
||||
: NO_REGS)
|
||||
|
||||
/* The letters I, J, K, L and M in a register constraint string
|
||||
@ -353,13 +472,15 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
|
||||
/* We return GENERAL_REGS instead of GEN_AND_MEM_REGS.
|
||||
The latter offers no real additional possibilities
|
||||
and can cause spurious secondary reloading. */
|
||||
and can cause spurious secondary reloading. */
|
||||
|
||||
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
|
||||
((CLASS) == GEN_AND_MEM_REGS ? GENERAL_REGS : (CLASS))
|
||||
|
||||
/* Return the maximum number of consecutive registers
|
||||
needed to represent mode MODE in a register of class CLASS. */
|
||||
/* On the 32000, this is the size of MODE in words */
|
||||
|
||||
#define CLASS_MAX_NREGS(CLASS, MODE) \
|
||||
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
||||
|
||||
@ -381,6 +502,46 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
of the first local allocated. */
|
||||
#define STARTING_FRAME_OFFSET 0
|
||||
|
||||
/* A C expression whose value is RTL representing the location of the
|
||||
incoming return address at the beginning of any function, before
|
||||
the prologue. This RTL is either a `REG', indicating that the
|
||||
return value is saved in `REG', or a `MEM' representing a location
|
||||
in the stack.
|
||||
|
||||
You only need to define this macro if you want to support call
|
||||
frame debugging information like that provided by DWARF 2.
|
||||
|
||||
Before the prologue, RA is at 0(sp). */
|
||||
|
||||
#define INCOMING_RETURN_ADDR_RTX \
|
||||
gen_rtx (MEM, VOIDmode, gen_rtx (REG, VOIDmode, STACK_POINTER_REGNUM))
|
||||
|
||||
/* A C expression whose value is RTL representing the value of the
|
||||
return address for the frame COUNT steps up from the current frame,
|
||||
after the prologue. FRAMEADDR is the frame pointer of the COUNT
|
||||
frame, or the frame pointer of the COUNT - 1 frame if
|
||||
`RETURN_ADDR_IN_PREVIOUS_FRAME' is defined.
|
||||
|
||||
After the prologue, RA is at 4(fp) in the current frame. */
|
||||
|
||||
#define RETURN_ADDR_RTX(COUNT, FRAME) \
|
||||
(gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, (FRAME), GEN_INT(4))))
|
||||
|
||||
/* A C expression whose value is an integer giving the offset, in
|
||||
bytes, from the value of the stack pointer register to the top of
|
||||
the stack frame at the beginning of any function, before the
|
||||
prologue. The top of the frame is defined to be the value of the
|
||||
stack pointer in the previous frame, just before the call
|
||||
instruction.
|
||||
|
||||
You only need to define this macro if you want to support call
|
||||
frame debugging information like that provided by DWARF 2. */
|
||||
|
||||
#define INCOMING_FRAME_SP_OFFSET 4
|
||||
|
||||
/* Offset of the CFA from the argument pointer register value. */
|
||||
#define ARG_POINTER_CFA_OFFSET 8
|
||||
|
||||
/* If we generate an insn to push BYTES bytes,
|
||||
this says how many the stack pointer really advances by.
|
||||
On the 32000, sp@- in a byte insn really pushes a BYTE. */
|
||||
@ -402,14 +563,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
because the library is compiled with the Unix compiler.
|
||||
Use of RET is a selectable option, since it is incompatible with
|
||||
standard Unix calling sequences. If the option is not selected,
|
||||
the caller must always pop the args. */
|
||||
the caller must always pop the args.
|
||||
|
||||
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
|
||||
((TARGET_RTD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \
|
||||
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|
||||
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
|
||||
== void_type_node))) \
|
||||
? (SIZE) : 0)
|
||||
The attribute stdcall is equivalent to RTD on a per module basis. */
|
||||
|
||||
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
|
||||
(ns32k_return_pops_args (FUNDECL, FUNTYPE, SIZE))
|
||||
|
||||
/* Define how to find the value returned by a function.
|
||||
VALTYPE is the data type of the value (as a tree).
|
||||
@ -417,23 +576,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
otherwise, FUNC is 0. */
|
||||
|
||||
/* On the 32000 the return value is in R0,
|
||||
or perhaps in F0 is there is fp support. */
|
||||
or perhaps in F0 if there is fp support. */
|
||||
|
||||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||||
(TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_32081 \
|
||||
? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \
|
||||
: gen_rtx (REG, TYPE_MODE (VALTYPE), 0))
|
||||
#define FUNCTION_VALUE(VALTYPE, FUNC) LIBCALL_VALUE(TYPE_MODE (VALTYPE))
|
||||
|
||||
/* Define how to find the value returned by a library function
|
||||
assuming the value has mode MODE. */
|
||||
|
||||
/* On the 32000 the return value is in R0,
|
||||
or perhaps F0 is there is fp support. */
|
||||
or perhaps F0 is there is fp support. */
|
||||
|
||||
#define LIBCALL_VALUE(MODE) \
|
||||
(((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \
|
||||
? gen_rtx (REG, MODE, 8) \
|
||||
: gen_rtx (REG, MODE, 0))
|
||||
gen_rtx (REG, MODE, \
|
||||
FLOAT_MODE_P(MODE) && TARGET_32081 ? F0_REGNUM: R0_REGNUM)
|
||||
|
||||
/* Define this if PCC uses the nonreentrant convention for returning
|
||||
structure and union values. */
|
||||
@ -554,18 +709,18 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
#define FUNCTION_PROLOGUE(FILE, SIZE) \
|
||||
{ register int regno, g_regs_used = 0; \
|
||||
int used_regs_buf[8], *bufp = used_regs_buf; \
|
||||
int used_fregs_buf[8], *fbufp = used_fregs_buf; \
|
||||
int used_fregs_buf[17], *fbufp = used_fregs_buf; \
|
||||
extern char call_used_regs[]; \
|
||||
extern int current_function_uses_pic_offset_table, flag_pic; \
|
||||
MAIN_FUNCTION_PROLOGUE; \
|
||||
for (regno = 0; regno < 8; regno++) \
|
||||
for (regno = R0_REGNUM; regno < F0_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] \
|
||||
&& ! call_used_regs[regno]) \
|
||||
{ \
|
||||
*bufp++ = regno; g_regs_used++; \
|
||||
} \
|
||||
*bufp = -1; \
|
||||
for (; regno < 16; regno++) \
|
||||
for (; regno < FRAME_POINTER_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] && !call_used_regs[regno]) \
|
||||
{ \
|
||||
*fbufp++ = regno; \
|
||||
@ -600,11 +755,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
fbufp = used_fregs_buf; \
|
||||
while (*fbufp >= 0) \
|
||||
{ \
|
||||
if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \
|
||||
fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \
|
||||
if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \
|
||||
fprintf (FILE, "\tmovf %s,tos\n", ns32k_out_reg_names[*fbufp++]); \
|
||||
else \
|
||||
{ \
|
||||
fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \
|
||||
fprintf (FILE, "\tmovl %s,tos\n", \
|
||||
ns32k_out_reg_names[fbufp[0]]); \
|
||||
fbufp += 2; \
|
||||
} \
|
||||
} \
|
||||
@ -678,19 +834,19 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
#define FUNCTION_EPILOGUE(FILE, SIZE) \
|
||||
{ register int regno, g_regs_used = 0, f_regs_used = 0; \
|
||||
int used_regs_buf[8], *bufp = used_regs_buf; \
|
||||
int used_fregs_buf[8], *fbufp = used_fregs_buf; \
|
||||
int used_fregs_buf[17], *fbufp = used_fregs_buf; \
|
||||
extern char call_used_regs[]; \
|
||||
extern int current_function_uses_pic_offset_table, flag_pic; \
|
||||
if (flag_pic && current_function_uses_pic_offset_table) \
|
||||
fprintf (FILE, "\tlprd sb,tos\n"); \
|
||||
*fbufp++ = -2; \
|
||||
for (regno = 8; regno < 16; regno++) \
|
||||
for (regno = F0_REGNUM; regno < FRAME_POINTER_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] && !call_used_regs[regno]) \
|
||||
{ \
|
||||
*fbufp++ = regno; f_regs_used++; \
|
||||
} \
|
||||
fbufp--; \
|
||||
for (regno = 0; regno < 8; regno++) \
|
||||
for (regno = 0; regno < F0_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] \
|
||||
&& ! call_used_regs[regno]) \
|
||||
{ \
|
||||
@ -698,12 +854,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
} \
|
||||
while (fbufp > used_fregs_buf) \
|
||||
{ \
|
||||
if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \
|
||||
if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \
|
||||
{ \
|
||||
fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \
|
||||
fprintf (FILE, "\tmovl tos,%s\n", \
|
||||
ns32k_out_reg_names[fbufp[-1]]); \
|
||||
fbufp -= 2; \
|
||||
} \
|
||||
else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \
|
||||
else fprintf (FILE, "\tmovf tos,%s\n", ns32k_out_reg_names[*fbufp--]); \
|
||||
} \
|
||||
if (frame_pointer_needed) \
|
||||
fprintf (FILE, "\texit ["); \
|
||||
@ -742,9 +899,12 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, GEN_AND_FP_REGS,
|
||||
int regno; \
|
||||
int offset = -4; \
|
||||
extern int current_function_uses_pic_offset_table, flag_pic; \
|
||||
for (regno = 0; regno < 16; regno++) \
|
||||
for (regno = 0; regno < L1_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
|
||||
offset += 4; \
|
||||
for (; regno < FRAME_POINTER_REGNUM; regno++) \
|
||||
if (regs_ever_live[regno] && ! call_used_regs[regno]) \
|
||||
offset += 8; \
|
||||
if (flag_pic && current_function_uses_pic_offset_table) \
|
||||
offset += 4; \
|
||||
(DEPTH) = (offset + get_frame_size () \
|
||||
@ -824,12 +984,13 @@ __transfer_from_trampoline () \
|
||||
|
||||
/* note that FP and SP cannot be used as an index. What about PC? */
|
||||
#define REGNO_OK_FOR_INDEX_P(REGNO) \
|
||||
((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8)
|
||||
((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM)
|
||||
#define REGNO_OK_FOR_BASE_P(REGNO) \
|
||||
((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \
|
||||
((REGNO) < F0_REGNUM || (unsigned)reg_renumber[REGNO] < F0_REGNUM \
|
||||
|| (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM)
|
||||
|
||||
#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16)
|
||||
#define FP_REG_P(X) \
|
||||
(GET_CODE (X) == REG && REGNO (X) >= F0_REGNUM && REGNO (X) < FRAME_POINTER_REGNUM)
|
||||
|
||||
/* Maximum number of registers that can appear in a valid memory address. */
|
||||
|
||||
@ -838,19 +999,18 @@ __transfer_from_trampoline () \
|
||||
/* Recognize any constant value that is a valid address.
|
||||
This might not work on future ns32k processors as negative
|
||||
displacements are not officially allowed but a mode reserved
|
||||
to National. This works on processors up to 32532, though. */
|
||||
to National. This works on processors up to 32532, though,
|
||||
and we don't expect any new ones in the series ;-( */
|
||||
|
||||
#define CONSTANT_ADDRESS_P(X) \
|
||||
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|
||||
|| GET_CODE (X) == CONST \
|
||||
|| (GET_CODE (X) == CONST_INT \
|
||||
&& ((unsigned)INTVAL (X) >= 0xe0000000 \
|
||||
|| (unsigned)INTVAL (X) < 0x20000000)))
|
||||
&& NS32K_DISPLACEMENT_P (INTVAL (X))))
|
||||
|
||||
#define CONSTANT_ADDRESS_NO_LABEL_P(X) \
|
||||
(GET_CODE (X) == CONST_INT \
|
||||
&& ((unsigned)INTVAL (X) >= 0xe0000000 \
|
||||
|| (unsigned)INTVAL (X) < 0x20000000))
|
||||
&& NS32K_DISPLACEMENT_P (INTVAL (X)))
|
||||
|
||||
/* Return the register class of a scratch register needed to copy IN into
|
||||
or out of a register in CLASS in MODE. If it can be done directly,
|
||||
@ -859,6 +1019,42 @@ __transfer_from_trampoline () \
|
||||
#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
|
||||
secondary_reload_class (CLASS, MODE, IN)
|
||||
|
||||
/* Certain machines have the property that some registers cannot be
|
||||
copied to some other registers without using memory. Define this
|
||||
macro on those machines to be a C expression that is non-zero if
|
||||
objects of mode M in registers of CLASS1 can only be copied to
|
||||
registers of class CLASS2 by storing a register of CLASS1 into
|
||||
memory and loading that memory location into a register of CLASS2.
|
||||
|
||||
On the ns32k, floating point regs can only be loaded through memory
|
||||
|
||||
The movdf and movsf insns in ns32k.md copy between general and
|
||||
floating registers using the stack. In principle, we could get
|
||||
better code not allowing that case in the constraints and defining
|
||||
SECONDARY_MEMORY_NEEDED in practice, though the stack slots used
|
||||
are not available for optimization. */
|
||||
|
||||
#if 0
|
||||
#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, M) \
|
||||
secondary_memory_needed(CLASS1, CLASS2, M)
|
||||
#endif
|
||||
|
||||
/* SMALL_REGISTER_CLASSES is true only if we have said we are using the
|
||||
* multiply-add instructions.
|
||||
*/
|
||||
#define SMALL_REGISTER_CLASSES (target_flags & 512)
|
||||
|
||||
/* A C expression whose value is nonzero if pseudos that have been
|
||||
assigned to registers of class CLASS would likely be spilled
|
||||
because registers of CLASS are needed for spill registers.
|
||||
|
||||
The default definition won't do because class LONG_FLOAT_REG0 has two
|
||||
registers which are always acessed as a pair */
|
||||
|
||||
#define CLASS_LIKELY_SPILLED_P(CLASS) \
|
||||
(reg_class_size[(int) (CLASS)] == 1 || (CLASS) == LONG_FLOAT_REG0)
|
||||
|
||||
|
||||
/* Nonzero if the constant value X is a legitimate general operand.
|
||||
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
|
||||
|
||||
@ -882,10 +1078,10 @@ __transfer_from_trampoline () \
|
||||
/* Nonzero if X is a hard reg that can be used as an index
|
||||
or if it is a pseudo reg. */
|
||||
#define REG_OK_FOR_INDEX_P(X) \
|
||||
(REGNO (X) < 8 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
|
||||
(REGNO (X) < F0_REGNUM || REGNO (X) >= FIRST_PSEUDO_REGISTER)
|
||||
/* Nonzero if X is a hard reg that can be used as a base reg
|
||||
of if it is a pseudo reg. */
|
||||
#define REG_OK_FOR_BASE_P(X) (REGNO (X) < 8 || REGNO (X) >= FRAME_POINTER_REGNUM)
|
||||
#define REG_OK_FOR_BASE_P(X) (REGNO (X) < F0_REGNUM || REGNO (X) >= FRAME_POINTER_REGNUM)
|
||||
/* Nonzero if X is a floating point reg or a pseudo reg. */
|
||||
|
||||
#else
|
||||
@ -936,7 +1132,8 @@ __transfer_from_trampoline () \
|
||||
|
||||
/* Check for frame pointer or stack pointer. */
|
||||
#define MEM_REG(X) \
|
||||
(GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2)
|
||||
(GET_CODE (X) == REG && (REGNO (X) == FRAME_POINTER_REGNUM \
|
||||
|| REGNO(X) == STACK_POINTER_REGNUM))
|
||||
|
||||
/* A memory ref whose address is the FP or SP, with optional integer offset,
|
||||
or (on certain machines) a constant address. */
|
||||
@ -1040,15 +1237,21 @@ __transfer_from_trampoline () \
|
||||
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
|
||||
|
||||
/* Nonzero if the constant value X is a legitimate general operand
|
||||
when generating PIC code. It is given that flag_pic is on and
|
||||
when generating PIC code. It is given that flag_pic is on and
|
||||
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
|
||||
|
||||
extern int current_function_uses_pic_offset_table, flag_pic;
|
||||
#define LEGITIMATE_PIC_OPERAND_P(X) \
|
||||
(((! current_function_uses_pic_offset_table \
|
||||
&& global_symbolic_reference_mentioned_p (X, 1))? \
|
||||
&& symbolic_reference_mentioned_p (X))? \
|
||||
(current_function_uses_pic_offset_table = 1):0 \
|
||||
), 1)
|
||||
), (! SYMBOLIC_CONST (X) \
|
||||
|| GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF))
|
||||
|
||||
#define SYMBOLIC_CONST(X) \
|
||||
(GET_CODE (X) == SYMBOL_REF \
|
||||
|| GET_CODE (X) == LABEL_REF \
|
||||
|| (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X)))
|
||||
|
||||
/* Define this macro if references to a symbol must be treated
|
||||
differently depending on something about the variable or
|
||||
@ -1082,6 +1285,33 @@ while (0)
|
||||
{ if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \
|
||||
goto LABEL;}
|
||||
|
||||
/* If defined, a C expression whose value is nonzero if IDENTIFIER
|
||||
with arguments ARGS is a valid machine specific attribute for DECL.
|
||||
The attributes in ATTRIBUTES have previously been assigned to DECL. */
|
||||
|
||||
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
|
||||
(ns32k_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
|
||||
|
||||
/* If defined, a C expression whose value is nonzero if IDENTIFIER
|
||||
with arguments ARGS is a valid machine specific attribute for TYPE.
|
||||
The attributes in ATTRIBUTES have previously been assigned to TYPE. */
|
||||
|
||||
#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \
|
||||
(ns32k_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
|
||||
|
||||
/* If defined, a C expression whose value is zero if the attributes on
|
||||
TYPE1 and TYPE2 are incompatible, one if they are compatible, and
|
||||
two if they are nearly compatible (which causes a warning to be
|
||||
generated). */
|
||||
|
||||
#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
|
||||
(ns32k_comp_type_attributes (TYPE1, TYPE2))
|
||||
|
||||
/* If defined, a C statement that assigns default attributes to newly
|
||||
defined TYPE. */
|
||||
|
||||
/* #define SET_DEFAULT_TYPE_ATTRIBUTES (TYPE) */
|
||||
|
||||
/* Specify the machine mode that this machine uses
|
||||
for the index in the tablejump instruction.
|
||||
HI mode is more efficient but the range is not wide enough for
|
||||
@ -1107,6 +1337,12 @@ while (0)
|
||||
in one reasonably fast instruction. */
|
||||
#define MOVE_MAX 4
|
||||
|
||||
/* The number of scalar move insns which should be generated instead
|
||||
of a string move insn or a library call.
|
||||
|
||||
We have a smart movstrsi insn */
|
||||
#define MOVE_RATIO 0
|
||||
|
||||
/* Define this if zero-extension is slow (more than one real instruction). */
|
||||
/* #define SLOW_ZERO_EXTEND */
|
||||
|
||||
@ -1226,16 +1462,13 @@ while (0)
|
||||
/* Describe the costs of the following register moves which are discouraged:
|
||||
1.) Moves between the Floating point registers and the frame pointer and stack pointer
|
||||
2.) Moves between the stack pointer and the frame pointer
|
||||
3.) Moves between the floating point and general registers */
|
||||
3.) Moves between the floating point and general registers
|
||||
|
||||
#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
|
||||
((((CLASS1) == FLOAT_REGS && ((CLASS2) == STACK_POINTER_REG || (CLASS2) == FRAME_POINTER_REG)) \
|
||||
|| ((CLASS2) == FLOAT_REGS && ((CLASS1) == STACK_POINTER_REG || (CLASS1) == FRAME_POINTER_REG)) \
|
||||
|| ((CLASS1) == STACK_POINTER_REG && (CLASS2) == FRAME_POINTER_REG) \
|
||||
|| ((CLASS2) == STACK_POINTER_REG && (CLASS1) == FRAME_POINTER_REG) \
|
||||
|| ((CLASS1) == FLOAT_REGS && (CLASS2) == GENERAL_REGS) \
|
||||
|| ((CLASS1) == GENERAL_REGS && (CLASS2) == FLOAT_REGS)) \
|
||||
? 4 : 2)
|
||||
These all involve two memory references. This is worse than a memory
|
||||
to memory move (default cost 4)
|
||||
*/
|
||||
|
||||
#define REGISTER_MOVE_COST(CLASS1, CLASS2) register_move_cost(CLASS1, CLASS2)
|
||||
|
||||
#define OUTPUT_JUMP(NORMAL, NO_OV) \
|
||||
{ if (cc_status.flags & CC_NO_OVERFLOW) \
|
||||
@ -1307,12 +1540,8 @@ while (0)
|
||||
/* This is how to output an assembler line defining an external/static
|
||||
address which is not in tree format (for collect.c). */
|
||||
|
||||
#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \
|
||||
do { \
|
||||
fprintf (STREAM, "\t.long\t"); \
|
||||
ASM_OUTPUT_LABELREF (STREAM, NAME); \
|
||||
fprintf (STREAM, "\n"); \
|
||||
} while (0)
|
||||
/* The prefix to add to user-visible assembler symbols. */
|
||||
#define USER_LABEL_PREFIX "_"
|
||||
|
||||
/* This is how to output an insn to push a register on the stack.
|
||||
It need not be very fast code. */
|
||||
@ -1326,19 +1555,6 @@ do { \
|
||||
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
|
||||
fprintf (FILE, "\tmovd tos,%s\n", reg_names[REGNO])
|
||||
|
||||
/* How to refer to registers in assembler output.
|
||||
This sequence is indexed by compiler's hard-register-number (see above). */
|
||||
|
||||
#define REGISTER_NAMES \
|
||||
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
|
||||
"fp", "sp"}
|
||||
|
||||
/* How to renumber registers for dbx and gdb.
|
||||
NS32000 may need more change in the numeration. */
|
||||
|
||||
#define DBX_REGISTER_NUMBER(REGNO) ((REGNO < 8) ? (REGNO)+4 : (REGNO))
|
||||
|
||||
/* This is how to output the definition of a user-level label named NAME,
|
||||
such as the label on a static function or variable NAME. */
|
||||
|
||||
@ -1365,9 +1581,11 @@ do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* The prefix to add to user-visible assembler symbols. */
|
||||
/* This is how to output a reference to a user-level label named NAME.
|
||||
`assemble_name' uses this. */
|
||||
|
||||
#define USER_LABEL_PREFIX "_"
|
||||
#define ASM_OUTPUT_LABELREF(FILE,NAME) \
|
||||
fprintf (FILE, "_%s", NAME)
|
||||
|
||||
/* This is how to output an internal numbered label where
|
||||
PREFIX is the class of label and NUM is the number within the class. */
|
||||
@ -1463,11 +1681,39 @@ do { \
|
||||
|
||||
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR)
|
||||
|
||||
/* Define functions in ns32k.c and used in insn-output.c. */
|
||||
/* Prototypes for functions in ns32k.c */
|
||||
|
||||
extern char *output_move_double ();
|
||||
extern char *output_shift_insn ();
|
||||
extern char *output_move_dconst ();
|
||||
/* Prototypes would be nice, but for now it causes too many problems.
|
||||
This file gets included in places where the types (such as "rtx"
|
||||
and enum machine_mode) are not defined. */
|
||||
#define NS32K_PROTO(ARGS) ()
|
||||
|
||||
int hard_regno_mode_ok NS32K_PROTO((int regno, enum machine_mode mode));
|
||||
int register_move_cost NS32K_PROTO((enum reg_class CLASS1, enum reg_class CLASS2));
|
||||
int calc_address_cost NS32K_PROTO((rtx operand));
|
||||
enum reg_class secondary_reload_class NS32K_PROTO((enum reg_class class,
|
||||
enum machine_mode mode, rtx in));
|
||||
int reg_or_mem_operand NS32K_PROTO((register rtx op, enum machine_mode mode));
|
||||
|
||||
void split_di NS32K_PROTO((rtx operands[], int num, rtx lo_half[], hi_half[]));
|
||||
|
||||
void expand_block_move NS32K_PROTO((rtx operands[]));
|
||||
int global_symbolic_reference_mentioned_p NS32K_PROTO((rtx op, int f));
|
||||
int ns32k_comp_type_attributes NS32K_PROTO((tree type1, tree type2));
|
||||
int ns32k_return_pops_args NS32K_PROTO((tree fundecl, tree funtype, int size));
|
||||
int ns32k_valid_decl_attribute_p NS32K_PROTO((tree decl, tree attributes,
|
||||
tree identifier, tree args));
|
||||
int ns32k_valid_type_attribute_p NS32K_PROTO((tree decl, tree attributes,
|
||||
tree identifier, tree args));
|
||||
void print_operand NS32K_PROTO((FILE *file, rtx x, char code));
|
||||
void print_operand_address NS32K_PROTO((register FILE *file, register rtx addr));
|
||||
char *output_move_dconst NS32K_PROTO((int n, char *s));
|
||||
char *output_move_double NS32K_PROTO((rtx *operands));
|
||||
char *output_shift_insn NS32K_PROTO((rtx *operands));
|
||||
|
||||
extern unsigned int ns32k_reg_class_contents[N_REG_CLASSES];
|
||||
extern char *ns32k_out_reg_names[];
|
||||
extern enum reg_class regclass_map[]; /* smalled class containing REGNO */
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
|
File diff suppressed because it is too large
Load Diff
121
gcc/invoke.texi
121
gcc/invoke.texi
@ -393,6 +393,11 @@ in the following sections.
|
||||
-mprolog-function -mno-prolog-function -mspace
|
||||
-mtda=@var{n} -msda=@var{n} -mzda=@var{n}
|
||||
-mv850 -mbig-switch
|
||||
|
||||
@emph{NS32K Options}
|
||||
-m32032 -m32332 -m32532 -m32081 -m32381 -mmult-add -mnomult-add
|
||||
-msoft-float -mrtd -mnortd -mregparam -mnoregparam -msb -mnosb
|
||||
-mbitfield -mnobitfield -mhimem -mnohimem
|
||||
@end smallexample
|
||||
|
||||
@item Code Generation Options
|
||||
@ -3055,6 +3060,7 @@ that macro, which enables you to change the defaults.
|
||||
* System V Options::
|
||||
* V850 Options::
|
||||
* ARC Options::
|
||||
* NS32K Options::
|
||||
@end menu
|
||||
|
||||
@node M680x0 Options
|
||||
@ -5678,6 +5684,121 @@ by default. This can be overridden with the @code{section} attribute.
|
||||
|
||||
@end table
|
||||
|
||||
@node NS32K Options
|
||||
@subsection NS32K Options
|
||||
@cindex NS32K options
|
||||
|
||||
These are the @samp{-m} options defined for the 32000 series. The default
|
||||
values for these options depends on which style of 32000 was selected when
|
||||
the compiler was configured; the defaults for the most common choices are
|
||||
given below.
|
||||
|
||||
@table @code
|
||||
@item -m32032
|
||||
@itemx -m32032
|
||||
Generate output for a 32032. This is the default
|
||||
when the compiler is configured for 32032 and 32016 based systems.
|
||||
|
||||
@item -m32332
|
||||
@itemx -m32332
|
||||
Generate output for a 32332. This is the default
|
||||
when the compiler is configured for 32332-based systems.
|
||||
|
||||
@item -m32532
|
||||
@itemx -m32532
|
||||
Generate output for a 32532. This is the default
|
||||
when the compiler is configured for 32532-based systems.
|
||||
|
||||
@item -m32081
|
||||
Generate output containing 32081 instructions for floating point.
|
||||
This is the default for all systems.
|
||||
|
||||
@item -m32381
|
||||
Generate output containing 32381 instructions for floating point. This
|
||||
also implies @samp{-m32081}. The 32381 is only compatible with the 32332
|
||||
and 32532 cpus. This is the default for the pc532-netbsd configuration.
|
||||
|
||||
@item -mmulti-add
|
||||
Try and generate multiply-add floating point instructions @code{polyF}
|
||||
and @code{dotF}. This option is only available if the @samp{-m32381}
|
||||
option is in effect. Using these instructions requires changes to to
|
||||
register allocation which generally has a negative impact on
|
||||
performance. This option should only be enabled when compiling code
|
||||
particularly likely to make heavy use of multiply-add instructions.
|
||||
|
||||
@item -mnomulti-add
|
||||
Do not try and generate multiply-add floating point instructions
|
||||
@code{polyF} and @code{dotF}. This is the default on all platforms.
|
||||
|
||||
@item -msoft-float
|
||||
Generate output containing library calls for floating point.
|
||||
@strong{Warning:} the requisite libraries may not be available.
|
||||
|
||||
@item -mnobitfield
|
||||
Do not use the bit-field instructions. On some machines it is faster to
|
||||
use shifting and masking operations. This is the default for the pc532.
|
||||
|
||||
@item -mbitfield
|
||||
Do use the bit-field instructions. This is the default for all platforms
|
||||
except the pc532.
|
||||
|
||||
@item -mrtd
|
||||
Use a different function-calling convention, in which functions
|
||||
that take a fixed number of arguments return pop their
|
||||
arguments on return with the @code{ret} instruction.
|
||||
|
||||
This calling convention is incompatible with the one normally
|
||||
used on Unix, so you cannot use it if you need to call libraries
|
||||
compiled with the Unix compiler.
|
||||
|
||||
Also, you must provide function prototypes for all functions that
|
||||
take variable numbers of arguments (including @code{printf});
|
||||
otherwise incorrect code will be generated for calls to those
|
||||
functions.
|
||||
|
||||
In addition, seriously incorrect code will result if you call a
|
||||
function with too many arguments. (Normally, extra arguments are
|
||||
harmlessly ignored.)
|
||||
|
||||
This option takes its name from the 680x0 @code{rtd} instruction.
|
||||
|
||||
|
||||
@item -mregparam
|
||||
Use a different function-calling convention where the first two arguments
|
||||
are passed in registers.
|
||||
|
||||
This calling convention is incompatible with the one normally
|
||||
used on Unix, so you cannot use it if you need to call libraries
|
||||
compiled with the Unix compiler.
|
||||
|
||||
@item -mnoregparam
|
||||
Do not pass any arguments in registers. This is the default for all
|
||||
targets.
|
||||
|
||||
@item -msb
|
||||
It is OK to use the sb as an index register which is always loaded with
|
||||
zero. This is the default for the pc532-netbsd target.
|
||||
|
||||
@item -mnosb
|
||||
The sb register is not available for use or has not been initialized to
|
||||
zero by the run time system. This is the default for all targets except
|
||||
the pc532-netbsd. It is also implied whenever @samp{-mhimem} or
|
||||
@samp{-fpic} is set.
|
||||
|
||||
@item -mhimem
|
||||
Many ns32000 series addressing modes use displacements of up to 512MB.
|
||||
If an address is above 512MB then displacements from zero can not be used.
|
||||
This option causes code to be generated which can be loaded above 512MB.
|
||||
This may be useful for operating systems or ROM code.
|
||||
|
||||
@item -mnohimem
|
||||
Assume code will be loaded in the first 512MB of virtual address space.
|
||||
This is the default for all platforms.
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
|
||||
@node Code Gen Options
|
||||
@section Options for Code Generation Conventions
|
||||
|
Loading…
Reference in New Issue
Block a user