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:
Ian Dall 1998-11-25 23:34:42 +00:00 committed by Richard Henderson
parent 36696297f1
commit 8357595779
7 changed files with 1481 additions and 486 deletions

View File

@ -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>

View File

@ -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

View File

@ -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> */

View File

@ -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
}

View File

@ -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

View File

@ -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