+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.
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.
(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
(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>
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
/* 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 */
/* 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> */
/* 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"
#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;
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. */
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++)
{
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))
- 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)
+ if ((class == FRAME_POINTER_REG && regno == STACK_POINTER_REGNUM)
+ || ( class == STACK_POINTER_REG && regno == FRAME_POINTER_REGNUM))
+ return GENERAL_REGS;
+ else
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;
{
|| GET_CODE (op) == SUBREG
|| GET_CODE (op) == MEM));
}
+
\f
/* Split one or more DImode RTL references into pairs of SImode
references. The RTL can be REG, offsettable MEM, integer constant, or
return singlemove_string (operands);
}
-int
-check_reg (oper, reg)
- rtx oper;
- int reg;
+\f
+#define MAX_UNALIGNED_COPY (32)
+/* Expand string/block move operations.
+
+ 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;
{
- register int i;
+ if (bytes & 2)
+ {
+ 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);
+ }
+}
- if (oper == 0)
- return 0;
- switch (GET_CODE(oper))
+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)
{
- 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);
+ 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));
}
- return 0;
}
+\f
/* Returns 1 if OP contains a global symbol reference */
}
\f
+/* 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;
+}
+\f
+/* 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;
+}
+
+\f
+/* 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;
+}
+\f
/* 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;
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);
}
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);
+ }
}
}
\f
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;
base = tmp;
break;
case REG:
- if (REGNO (tmp) < 8)
+ if (REGNO (tmp) < F0_REGNUM)
if (base)
{
indexexp = tmp;
(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)
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
}
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
}
/* 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)"
/* 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
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}, \
{ "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)
+
\f
/* target machine storage layout */
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.
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)
/* 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. */
-
-/* NS32000 pc is not overloaded on a register. */
-/* #define PC_REGNUM */
+ 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. */
-/* 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
#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
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. */
/* 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
/* 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)
\f
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. */
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.
+
+ The attribute stdcall is equivalent to RTD on a per module basis. */
-#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)
+#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).
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. */
#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; \
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; \
} \
} \
#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]) \
{ \
} \
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 ["); \
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 () \
/* 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)
\f
/* Maximum number of registers that can appear in a valid memory address. */
/* 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,
#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. */
/* 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
/* 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. */
#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
{ if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \
goto LABEL;}
\f
+/* 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) */
+\f
/* 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
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 */
/* 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
+
+ These all involve two memory references. This is worse than a memory
+ to memory move (default cost 4)
+ */
-#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)
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) register_move_cost(CLASS1, CLASS2)
#define OUTPUT_JUMP(NORMAL, NO_OV) \
{ if (cc_status.flags & CC_NO_OVERFLOW) \
/* 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. */
#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. */
} 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. */
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR)
-/* Define functions in ns32k.c and used in insn-output.c. */
-
-extern char *output_move_double ();
-extern char *output_shift_insn ();
-extern char *output_move_dconst ();
+/* Prototypes for functions in ns32k.c */
+
+/* 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:
;; We don't want to allow a constant operand for test insns because
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
;; be folded while optimizing anyway.
-
+;;
+;; In order for pic mode to work we cannot generate, for example
+;;
+;; addd _x+5,r1
+;;
+;; instead we must force gcc to generate something like
+;;
+;; addr 5(_x(sb)),r0
+;; addd r0,r1
+;;
+;; This was done through operand constraints (using "rmn" in place of "g"),
+;; but with the proper definition of LEGITIMATE_PIC_OPERAND (ns32k.h)
+;; this is unnecessary.
+;;
(define_insn "tstsi"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
(define_insn "tstdf"
[(set (cc0)
- (match_operand:DF 0 "general_operand" "fmF"))]
+ (match_operand:DF 0 "general_operand" "lmF"))]
"TARGET_32081"
"*
{ cc_status.flags |= CC_REVERSED;
operands[1] = CONST0_RTX (SFmode);
return \"cmpf %1,%0\"; }")
+;; See note 1
(define_insn "cmpsi"
[(set (cc0)
- (compare (match_operand:SI 0 "nonimmediate_operand" "rmn")
- (match_operand:SI 1 "general_operand" "rmn")))]
+ (compare (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g")))]
""
"*
{
(define_insn "cmphi"
[(set (cc0)
- (compare (match_operand:HI 0 "nonimmediate_operand" "g")
+ (compare (match_operand:HI 0 "general_operand" "g")
(match_operand:HI 1 "general_operand" "g")))]
""
"*
(define_insn "cmpqi"
[(set (cc0)
- (compare (match_operand:QI 0 "nonimmediate_operand" "g")
+ (compare (match_operand:QI 0 "general_operand" "g")
(match_operand:QI 1 "general_operand" "g")))]
""
"*
(define_insn "cmpdf"
[(set (cc0)
- (compare (match_operand:DF 0 "general_operand" "fmF")
- (match_operand:DF 1 "general_operand" "fmF")))]
+ (compare (match_operand:DF 0 "general_operand" "lmF")
+ (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"cmpl %0,%1")
"TARGET_32081"
"cmpf %0,%1")
\f
+;; movdf and movsf 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.
(define_insn "movdf"
- [(set (match_operand:DF 0 "general_operand" "=fg<")
- (match_operand:DF 1 "general_operand" "fFg"))]
+ [(set (match_operand:DF 0 "general_operand" "=lg<")
+ (match_operand:DF 1 "general_operand" "lFg"))]
""
"*
{
{
if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,tos\;movf tos,%0\";
else
return \"movf %1,%0\";
;; This special case must precede movsi.
(define_insn ""
- [(set (reg:SI 17)
- (match_operand:SI 0 "general_operand" "rmn"))]
+ [(set (reg:SI 25)
+ (match_operand:SI 0 "general_operand" "g"))]
""
"lprd sp,%0")
if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,tos\;movf tos,%0\";
else
return \"movf %1,%0\";
{
if (i <= 7 && i >= -8)
return \"movqd %1,%0\";
- if (i <= 0x1fffffff && i >= -0x20000000)
+ if (NS32K_DISPLACEMENT_P (i))
#if defined (GNX_V3) || defined (UTEK_ASM)
return \"addr %c1,%0\";
#else
return \"addr @%c1,%0\";
#endif
- return \"movd %$%1,%0\";
+ return \"movd %1,%0\";
}
else
- return output_move_dconst(i, \"%$%1,%0\");
+ return output_move_dconst(i, \"%1,%0\");
}
else if (GET_CODE (operands[1]) == CONST && ! flag_pic)
{
* that case addr might lead to overflow. For PIC symbolic
* address loads always have to be done with addr.
*/
- return \"movd %$%1,%0\";
+ return \"movd %1,%0\";
}
else if (GET_CODE (operands[1]) == REG)
{
- if (REGNO (operands[1]) < 16)
+ if (REGNO (operands[1]) < F0_REGNUM)
return \"movd %1,%0\";
else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM)
{
}
else if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movwf %1,tos\;movf tos,%0\";
else
return \"movwf %1,%0\";
}
else if (FP_REG_P (operands[0]))
{
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8)
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < F0_REGNUM)
return \"movbf %1,tos\;movf tos,%0\";
else
return \"movbf %1,%0\";
return \"movb %1,%0\";
}")
\f
-;; This is here to accept 4 arguments and pass the first 3 along
-;; to the movstrsi1 pattern that really does the work.
+;; Block moves
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+;;
+;; Strategy: Use define_expand to
+;; either emit insns directly if it can be done simply or
+;; emit rtl to match movstrsi1 which has extra scratch registers
+;; which can be used to generate more complex code.
+
(define_expand "movstrsi"
- [(set (match_operand:BLK 0 "general_operand" "=g")
- (match_operand:BLK 1 "general_operand" "g"))
- (use (match_operand:SI 2 "general_operand" "rmn"))
- (match_operand 3 "" "")]
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" ""))
+ (use (match_operand:SI 2 "general_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
""
"
- emit_insn (gen_movstrsi1 (operands[0], operands[1], operands[2]));
- DONE;
-")
+{
+ if (operands[0]) /* avoid unused code messages */
+ {
+ expand_block_move (operands);
+ DONE;
+ }
+}")
+
+;; Special Registers:
+;; r0 count
+;; r1 from
+;; r2 to
+;; r3 match
+
-;; The definition of this insn does not really explain what it does,
-;; but it should suffice
-;; that anything generated as this insn will be recognized as one
-;; and that it won't successfully combine with anything.
(define_insn "movstrsi1"
- [(set (match_operand:BLK 0 "general_operand" "=g")
- (match_operand:BLK 1 "general_operand" "g"))
- (use (match_operand:SI 2 "general_operand" "rmn"))
- (clobber (reg:SI 0))
- (clobber (reg:SI 1))
- (clobber (reg:SI 2))]
+ [(set (mem:BLK (reg:SI 2))
+ (mem:BLK (reg:SI 1)))
+ (use (reg:SI 0))
+ (set (reg:SI 2) (plus:SI (reg:SI 2) (mult:SI (reg:SI 0) (match_operand:SI 0 "const_int_operand" ""))))
+ (set (reg:SI 1) (plus:SI (reg:SI 1) (mult:SI (reg:SI 0) (match_dup 0))))
+ (set (reg:SI 0) (const_int 0))]
""
"*
-{
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- abort ();
- operands[0] = XEXP (operands[0], 0);
- operands[1] = XEXP (operands[1], 0);
- if (GET_CODE (operands[0]) == MEM)
- if (GET_CODE (operands[1]) == MEM)
- output_asm_insn (\"movd %0,r2\;movd %1,r1\", operands);
- else
- output_asm_insn (\"movd %0,r2\;addr %a1,r1\", operands);
- else if (GET_CODE (operands[1]) == MEM)
- output_asm_insn (\"addr %a0,r2\;movd %1,r1\", operands);
- else
- output_asm_insn (\"addr %a0,r2\;addr %a1,r1\", operands);
+ {
+ int align = INTVAL(operands[0]);
+ if (align == 4)
+ return \"movsd\";
+ else
+ return \"movsb\";
+ }")
+
+(define_insn "movstrsi2"
+ [(set (mem:BLK (match_operand:SI 0 "address_operand" "g"))
+ (mem:BLK (match_operand:SI 1 "address_operand" "g")))
+ (use (match_operand 2 "immediate_operand" "i"))]
+ ""
+ "movmd %a1,%a0,%2")
-#ifdef UTEK_ASM
- if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0)
- {
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 2);
- if ((unsigned) INTVAL (operands[2]) <= 7)
- return \"movqd %2,r0\;movsd $0\";
- else
- return \"movd %2,r0\;movsd $0\";
- }
- else
- {
- return \"movd %2,r0\;movsb $0\";
- }
-#else
- if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0)
- {
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 2);
- if ((unsigned) INTVAL (operands[2]) <= 7)
- return \"movqd %2,r0\;movsd\";
- else
- return \"movd %2,r0\;movsd\";
- }
- else
- {
- return \"movd %2,r0\;movsb\";
- }
-#endif
-}")
\f
;; Extension and truncation insns.
;; Those for integer source operand
(define_insn "truncsiqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rmn")))]
+ (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "g")))]
""
"movb %1,%0")
(define_insn "truncsihi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rmn")))]
+ (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "g")))]
""
"movw %1,%0")
"movxbd %1,%0")
(define_insn "extendsfdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float_extend:DF (match_operand:SF 1 "general_operand" "fmF")))]
"TARGET_32081"
"movfl %1,%0")
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "general_operand" "=fm<")
- (float_truncate:SF (match_operand:DF 1 "general_operand" "fmF")))]
+ (float_truncate:SF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"movlf %1,%0")
"movdf %1,%0")
(define_insn "floatsidf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float:DF (match_operand:SI 1 "general_operand" "rm")))]
"TARGET_32081"
"movdl %1,%0")
"movwf %1,%0")
(define_insn "floathidf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
(float:DF (match_operand:HI 1 "general_operand" "rm")))]
"TARGET_32081"
"movwl %1,%0")
; Some assemblers warn that this insn doesn't work.
; Maybe they know something we don't.
;(define_insn "floatqidf2"
-; [(set (match_operand:DF 0 "general_operand" "=fm<")
+; [(set (match_operand:DF 0 "general_operand" "=lm<")
; (float:DF (match_operand:QI 1 "general_operand" "rm")))]
; "TARGET_32081"
; "movbl %1,%0")
(define_insn "fixdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fixdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fixdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"truncld %1,%0")
(define_insn "fixunsdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:QI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fixunsdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:HI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fixunsdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))]
+ (unsigned_fix:SI (fix:DF (match_operand:DF 1 "general_operand" "lm"))))]
"TARGET_32081"
"truncld %1,%0")
(define_insn "fix_truncdfqi2"
[(set (match_operand:QI 0 "general_operand" "=g<")
- (fix:QI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:QI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"trunclb %1,%0")
(define_insn "fix_truncdfhi2"
[(set (match_operand:HI 0 "general_operand" "=g<")
- (fix:HI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:HI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"trunclw %1,%0")
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (fix:SI (match_operand:DF 1 "general_operand" "fm")))]
+ (fix:SI (match_operand:DF 1 "general_operand" "lm")))]
"TARGET_32081"
"truncld %1,%0")
\f
+;; Multiply-add instructions
+(define_insn ""
+ [(set (match_operand:DF 0 "general_operand" "=v,v")
+ (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF,0")
+ (match_operand:DF 2 "general_operand" "lmF,lmF"))
+ (match_operand:DF 3 "general_operand" "0,lmF")))]
+ "TARGET_MULT_ADD"
+ "@
+ dotl %1,%2
+ polyl %2,%3")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "general_operand" "=u,u")
+ (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF,0")
+ (match_operand:SF 2 "general_operand" "fmF,fmF"))
+ (match_operand:SF 3 "general_operand" "0,fmF")))]
+ "TARGET_MULT_ADD"
+ "@
+ dotf %1,%2
+ polyf %2,%3")
+
+
+;; Multiply-sub instructions
+(define_insn ""
+ [(set (match_operand:DF 0 "general_operand" "=v")
+ (minus:DF (mult:DF (match_operand:DF 1 "general_operand" "%lmF")
+ (match_operand:DF 2 "general_operand" "lmF"))
+ (match_operand:DF 3 "general_operand" "0")))]
+ "TARGET_MULT_ADD"
+ "@
+ negl %0,%0\;dotl %1,%2")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "general_operand" "=u")
+ (minus:SF (mult:SF (match_operand:SF 1 "general_operand" "%fmF")
+ (match_operand:SF 2 "general_operand" "fmF"))
+ (match_operand:SF 3 "general_operand" "0")))]
+ "TARGET_MULT_ADD"
+ "@
+ negf %0,%0\;dotf %1,%2")
+
;;- All kinds of add instructions.
(define_insn "adddf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(plus:DF (match_operand:DF 1 "general_operand" "%0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"addl %2,%0")
"addf %2,%0")
(define_insn ""
- [(set (reg:SI 17)
- (plus:SI (reg:SI 17)
+ [(set (reg:SI 25)
+ (plus:SI (reg:SI 25)
(match_operand:SI 0 "immediate_operand" "i")))]
"GET_CODE (operands[0]) == CONST_INT"
"*
if (! TARGET_32532)
{
if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64)
- return \"adjspb %$%n0\";
+ return \"adjspb %n0\";
else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192)
- return \"adjspw %$%n0\";
+ return \"adjspw %n0\";
}
- return \"adjspd %$%n0\";
+ return \"adjspd %n0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g<")
- (plus:SI (reg:SI 16)
+ (plus:SI (reg:SI 24)
(match_operand:SI 1 "immediate_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT"
"addr %c1(fp),%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g<")
- (plus:SI (reg:SI 17)
+ (plus:SI (reg:SI 25)
(match_operand:SI 1 "immediate_operand" "i")))]
"GET_CODE (operands[1]) == CONST_INT"
"addr %c1(sp),%0")
{
i = INTVAL (xops[3]);
if (i <= 7 && i >= -8)
- output_asm_insn (\"addqd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %3,%1\", xops);
else
- output_asm_insn (\"addd %$%3,%1\", xops);
+ output_asm_insn (\"addd %3,%1\", xops);
}
else
{
- output_asm_insn (\"addqd %$%2,%0\", xops);
- output_asm_insn (\"addcd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %2,%0\", xops);
+ output_asm_insn (\"addcd %3,%1\", xops);
}
return \"\";
}
return \"\";
}")
+;; See Note 1
(define_insn "addsi3"
[(set (match_operand:SI 0 "general_operand" "=g,=g&<")
(plus:SI (match_operand:SI 1 "general_operand" "%0,r")
- (match_operand:SI 2 "general_operand" "rmn,n")))]
+ (match_operand:SI 2 "general_operand" "g,i")))]
""
"*
{
if (which_alternative == 1)
{
- int i = INTVAL (operands[2]);
- if (NS32K_DISPLACEMENT_P (i))
- return \"addr %c2(%1),%0\";
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ int i = INTVAL (operands[2]);
+ if (NS32K_DISPLACEMENT_P (i))
+ return \"addr %c2(%1),%0\";
+ else
+ return \"movd %1,%0\;addd %2,%0\";
+ }
else
- return \"movd %1,%0\;addd %2,%0\";
+ {
+ if (flag_pic)
+ return \"addr %a2[%1:b],%0\";
+ else
+ return \"addr %c2(%1),%0\";
+ }
}
- if (GET_CODE (operands[2]) == CONST_INT)
+ else if (GET_CODE (operands[2]) == CONST_INT)
{
int i = INTVAL (operands[2]);
if (i <= 7 && i >= -8)
return \"addqd %2,%0\";
else if (! TARGET_32532 && GET_CODE (operands[0]) == REG
- && i <= 0x1fffffff && i >= -0x20000000)
+ && NS32K_DISPLACEMENT_P (i))
return \"addr %c2(%0),%0\";
}
return \"addd %2,%0\";
;;- All kinds of subtract instructions.
(define_insn "subdf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(minus:DF (match_operand:DF 1 "general_operand" "0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"subl %2,%0")
"subf %2,%0")
(define_insn ""
- [(set (reg:SI 17)
- (minus:SI (reg:SI 17)
+ [(set (reg:SI 25)
+ (minus:SI (reg:SI 25)
(match_operand:SI 0 "immediate_operand" "i")))]
"GET_CODE (operands[0]) == CONST_INT"
"*
{
if (! TARGET_32532 && GET_CODE(operands[0]) == CONST_INT
&& INTVAL(operands[0]) < 64 && INTVAL(operands[0]) > -64)
- return \"adjspb %$%0\";
- return \"adjspd %$%0\";
+ return \"adjspb %0\";
+ return \"adjspd %0\";
}")
(define_insn "subdi3"
{
i = INTVAL (xops[3]);
if (i <= 8 && i >= -7)
- output_asm_insn (\"addqd %$%n3,%1\", xops);
+ output_asm_insn (\"addqd %n3,%1\", xops);
else
- output_asm_insn (\"subd %$%3,%1\", xops);
+ output_asm_insn (\"subd %3,%1\", xops);
}
else
{
- output_asm_insn (\"addqd %$%n2,%0\", xops);
- output_asm_insn (\"subcd %$%3,%1\", xops);
+ output_asm_insn (\"addqd %n2,%0\", xops);
+ output_asm_insn (\"subcd %3,%1\", xops);
}
return \"\";
}
(define_insn "subsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(minus:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqd %$%n2,%0\";
+ return \"addqd %n2,%0\";
}
return \"subd %2,%0\";
}")
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqw %$%n2,%0\";
+ return \"addqw %n2,%0\";
}
return \"subw %2,%0\";
}")
{
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9)
- return \"addqw %$%n2,%0\";
+ return \"addqw %n2,%0\";
return \"subw %2,%0\";
}")
int i = INTVAL (operands[2]);
if (i <= 8 && i >= -7)
- return \"addqb %$%n2,%0\";
+ return \"addqb %n2,%0\";
}
return \"subb %2,%0\";
}")
{
if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9)
- return \"addqb %$%n2,%0\";
+ return \"addqb %n2,%0\";
return \"subb %2,%0\";
}")
\f
;;- Multiply instructions.
(define_insn "muldf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(mult:DF (match_operand:DF 1 "general_operand" "%0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"mull %2,%0")
"TARGET_32081"
"mulf %2,%0")
+;; See note 1
(define_insn "mulsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(mult:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"muld %2,%0")
(mult:DI (zero_extend:DI
(match_operand:SI 1 "nonimmediate_operand" "0"))
(zero_extend:DI
- (match_operand:SI 2 "nonimmediate_operand" "rmn"))))]
+ (match_operand:SI 2 "nonimmediate_operand" "g"))))]
""
"meid %2,%0")
\f
+;; divmod insns: We can only do the unsigned case.
+(define_expand "udivmodsi4"
+ [(parallel
+ [(set (match_operand:SI 0 "reg_or_mem_operand" "")
+ (udiv:SI (match_operand:SI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")))
+ (set (match_operand:SI 3 "reg_or_mem_operand" "")
+ (umod:SI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(SImode, temp), operands[1]);
+ emit_move_insn(gen_highpart(SImode, temp), const0_rtx);
+ emit_insn(gen_udivmoddisi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divsi, modsi;
+ divsi = gen_rtx (UDIV, SImode, operands[1], operands[2]);
+ modsi = gen_rtx (UMOD, SImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divsi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modsi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx (IOR, DImode, moddi,
+ gen_rtx (ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(SImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(SImode, temp));
+ DONE;
+}")
+
+;; If we try and describe what this does, we have to zero-expand an
+;; operand, which prevents it being a constant (VOIDmode) (see udivmoddisi4
+;; below. This udivmoddisi4_internal never matches anything and is only
+;; ever used when explicitly emitted by a define_expand.
+(define_insn "udivmoddisi4_internal"
+ [(set (match_operand:DI 0 "reg_or_mem_operand" "=rm")
+ (unspec:SI [(match_operand:DI 1 "reg_or_mem_operand" "0")
+ (match_operand:SI 2 "general_operand" "g")] 0))]
+ ""
+ "deid %2,%0")
+
+;; Retain this insn which *does* have a pattern indicating what it does,
+;; just in case the compiler is smart enough to recognize a substitution.
+(define_insn "udivmoddisi4"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "=rm") 1)
+ (truncate:SI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:SI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:SI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deid %2,%0")
+
+;; Part word variants. These seem to never be used at the moment (gcc
+;; 2.7.2.2). The code generation prefers to zero extend hi's and qi's
+;; and use signed div and mod. Keep these insns incase that changes.
+;; divmod should have an advantage when both div and mod are needed. However,
+;; divmod uses two registers, so maybe the compiler knows best.
+
+(define_expand "udivmodhi4"
+ [(parallel
+ [(set (match_operand:HI 0 "reg_or_mem_operand" "")
+ (udiv:HI (match_operand:HI 1 "general_operand" "")
+ (match_operand:HI 2 "general_operand" "")))
+ (set (match_operand:HI 3 "reg_or_mem_operand" "")
+ (umod:HI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(HImode, temp), operands[1]);
+ emit_move_insn(gen_highpart (HImode, temp), const0_rtx);
+ operands[2] = force_reg(HImode, operands[2]);
+ emit_insn(gen_udivmoddihi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divhi, modhi;
+ divhi = gen_rtx (UDIV, HImode, operands[1], operands[2]);
+ modhi = gen_rtx (UMOD, HImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divhi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modhi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx(IOR, DImode, moddi,
+ gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(HImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(HImode, temp));
+ DONE;
+}")
+
+;; deiw wants two hi's in seperate registers or else they can be adjacent
+;; in memory. DI mode will ensure two registers are available, but if we
+;; want to allow memory as an operand we would need SI mode. There is no
+;; way to do this, so just restrict operand 0 and 1 to be in registers.
+(define_insn "udivmoddihi4_internal"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:DI 1 "register_operand" "0")
+ (match_operand:HI 2 "general_operand" "g")] 0))]
+ ""
+ "deiw %2,%0")
+
+(define_insn "udivmoddihi4"
+ [(set (subreg:HI (match_operand:DI 0 "register_operand" "=r") 1)
+ (truncate:HI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:HI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:HI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:HI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deiw %2,%0")
+
+(define_expand "udivmodqi4"
+ [(parallel
+ [(set (match_operand:QI 0 "reg_or_mem_operand" "")
+ (udiv:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))
+ (set (match_operand:QI 3 "reg_or_mem_operand" "")
+ (umod:QI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx(DImode);
+ rtx insn, first, last;
+ first = emit_move_insn(gen_lowpart(QImode, temp), operands[1]);
+ emit_move_insn(gen_highpart(QImode, temp), const0_rtx);
+ operands[2] = force_reg(QImode, operands[2]);
+ emit_insn(gen_udivmoddiqi4_internal(temp, temp, operands[2]));
+ last = emit_move_insn(temp, temp);
+ {
+ rtx divdi, moddi, divqi, modqi;
+ divqi = gen_rtx (UDIV, QImode, operands[1], operands[2]);
+ modqi = gen_rtx (UMOD, QImode, operands[1], operands[2]);
+ divdi = gen_rtx (ZERO_EXTEND, DImode, divqi);
+ moddi = gen_rtx (ZERO_EXTEND, DImode, modqi);
+ REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first,
+ gen_rtx (EXPR_LIST, REG_EQUAL,
+ gen_rtx(IOR, DImode, moddi,
+ gen_rtx(ASHIFT, DImode, divdi, GEN_INT(32))),
+ REG_NOTES (last)));
+ }
+
+ insn = emit_move_insn(operands[0], gen_highpart(QImode, temp));
+ insn = emit_move_insn(operands[3], gen_lowpart(QImode, temp));
+ DONE;
+}")
+
+;; deib wants two qi's in seperate registers or else they can be adjacent
+;; in memory. DI mode will ensure two registers are available, but if we
+;; want to allow memory as an operand we would need HI mode. There is no
+;; way to do this, so just restrict operand 0 and 1 to be in registers.
+(define_insn "udivmoddiqi4_internal"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:QI [(match_operand:DI 1 "reg_or_mem_operand" "0")
+ (match_operand:QI 2 "general_operand" "g")] 0))]
+ ""
+ "deib %2,%0")
+
+(define_insn "udivmoddiqi4"
+ [(set (subreg:QI (match_operand:DI 0 "register_operand" "=r") 1)
+ (truncate:QI (udiv:DI (match_operand:DI 1 "reg_or_mem_operand" "0")
+ (zero_extend:DI (match_operand:QI 2 "nonimmediate_operand" "g")))))
+ (set (subreg:QI (match_operand:DI 3 "register_operand" "=0") 0)
+ (truncate:QI (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))]
+ ""
+ "deib %2,%0")
+\f
;;- Divide instructions.
(define_insn "divdf3"
- [(set (match_operand:DF 0 "general_operand" "=fm")
+ [(set (match_operand:DF 0 "general_operand" "=lm")
(div:DF (match_operand:DF 1 "general_operand" "0")
- (match_operand:DF 2 "general_operand" "fmF")))]
+ (match_operand:DF 2 "general_operand" "lmF")))]
"TARGET_32081"
"divl %2,%0")
"TARGET_32081"
"divf %2,%0")
+;; See note 1
(define_insn "divsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(div:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"quod %2,%0")
(match_operand:QI 2 "general_operand" "g")))]
""
"quob %2,%0")
-
-(define_insn "udivsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (udiv:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:SI 2 "general_operand" "rmn")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- return \"deid %2,%0\;movd %1,%0\";
-}")
-
-(define_insn "udivhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (udiv:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:HI 2 "general_operand" "g")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
- return \"deiw %2,%0\;movw %1,%0\";
-}")
-
-(define_insn "udivqi3"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (udiv:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:QI 2 "general_operand" "g")))]
- ""
- "*
-{
- operands[1] = gen_rtx (REG, QImode, REGNO (operands[0]) + 1);
- return \"deib %2,%0\;movb %1,%0\";
-}")
-
+\f
;; Remainder instructions.
+;; See note 1
(define_insn "modsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(mod:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"remd %2,%0")
""
"remb %2,%0")
-(define_insn "umodsi3"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (umod:SI (subreg:SI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:SI 2 "general_operand" "rmn")))]
- ""
- "deid %2,%0")
-
-(define_insn "umodhi3"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (umod:HI (subreg:HI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:HI 2 "general_operand" "g")))]
- ""
- "deiw %2,%0")
-
-(define_insn "umodqi3"
- [(set (match_operand:QI 0 "register_operand" "=r")
- (umod:QI (subreg:QI (match_operand:DI 1 "reg_or_mem_operand" "0") 0)
- (match_operand:QI 2 "general_operand" "g")))]
- ""
- "deib %2,%0")
-
-; This isn't be usable in its current form.
-;(define_insn "udivmoddisi4"
-; [(set (subreg:SI (match_operand:DI 0 "general_operand" "=r") 1)
-; (udiv:SI (match_operand:DI 1 "general_operand" "0")
-; (match_operand:SI 2 "general_operand" "rmn")))
-; (set (subreg:SI (match_dup 0) 0)
-; (umod:SI (match_dup 1) (match_dup 2)))]
-; ""
-; "deid %2,%0")
\f
;;- Logical Instructions: AND
+;; See note 1
(define_insn "andsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(and:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
""
"andb %2,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
- (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn"))
+ (and:SI (not:SI (match_operand:SI 1 "general_operand" "g"))
(match_operand:SI 2 "general_operand" "0")))]
""
"bicd %1,%0")
\f
;;- Bit set instructions.
+;; See note 1
(define_insn "iorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(ior:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
;;- xor instructions.
+;; See note 1
(define_insn "xorsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(xor:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{
"xorb %2,%0")
\f
(define_insn "negdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
- (neg:DF (match_operand:DF 1 "general_operand" "fmF")))]
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
+ (neg:DF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"negl %1,%0")
return \"\";
}")
+;; See note 1
(define_insn "negsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (neg:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (neg:SI (match_operand:SI 1 "general_operand" "g")))]
""
"negd %1,%0")
""
"negb %1,%0")
\f
+;; See note 1
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (not:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (not:SI (match_operand:SI 1 "general_operand" "g")))]
""
"comd %1,%0")
;; than elsewhere.
;; alternative 0 never matches on the 32532
+;; See note 1
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "general_operand" "=g,g")
(ashift:SI (match_operand:SI 1 "general_operand" "r,0")
- (match_operand:SI 2 "general_operand" "I,rmn")))]
+ (match_operand:SI 2 "general_operand" "I,g")))]
""
"*
{ if (TARGET_32532)
(define_insn "ashlhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(ashift:HI (match_operand:HI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
(define_insn "ashlqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(ashift:QI (match_operand:QI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"*
{ if (GET_CODE (operands[2]) == CONST_INT)
(ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashd %$%n2,%0")
+ "ashd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashw %$%n2,%0")
+ "ashw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
(ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "ashb %$%n2,%0")
+ "ashb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshd %$%n2,%0")
+ "lshd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshw %$%n2,%0")
+ "lshw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
(lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "lshb %$%n2,%0")
+ "lshb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
;; Rotate instructions
+;; See note 1
(define_insn "rotlsi3"
[(set (match_operand:SI 0 "general_operand" "=g")
(rotate:SI (match_operand:SI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotd %2,%0")
(define_insn "rotlhi3"
[(set (match_operand:HI 0 "general_operand" "=g")
(rotate:HI (match_operand:HI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotw %2,%0")
(define_insn "rotlqi3"
[(set (match_operand:QI 0 "general_operand" "=g")
(rotate:QI (match_operand:QI 1 "general_operand" "0")
- (match_operand:SI 2 "general_operand" "rmn")))]
+ (match_operand:SI 2 "general_operand" "g")))]
""
"rotb %2,%0")
(rotatert:SI (match_operand:SI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotd %$%n2,%0")
+ "rotd %n2,%0")
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g")
(rotatert:HI (match_operand:HI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotw %$%n2,%0")
+ "rotw %n2,%0")
(define_insn ""
[(set (match_operand:HI 0 "general_operand" "=g")
(rotatert:QI (match_operand:QI 1 "general_operand" "0")
(match_operand:SI 2 "immediate_operand" "i")))]
""
- "rotb %$%n2,%0")
+ "rotb %n2,%0")
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
;;; Index insns. These are about the same speed as multiply-add counterparts.
;;; but slower then using power-of-2 shifts if we can use them
;
+;;; See note 1
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
-; (plus:SI (match_operand:SI 1 "general_operand" "rmn")
+; (plus:SI (match_operand:SI 1 "general_operand" "g")
; (mult:SI (match_operand:SI 2 "register_operand" "0")
-; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (const_int 1)))))]
+; (plus:SI (match_operand:SI 3 "general_operand" "g") (const_int 1)))))]
; "GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) > 8"
; "indexd %0,%3,%1")
;
;(define_insn ""
; [(set (match_operand:SI 0 "register_operand" "=r")
; (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
-; (plus:SI (match_operand:SI 2 "general_operand" "rmn") (const_int 1)))
-; (match_operand:SI 3 "general_operand" "rmn")))]
+; (plus:SI (match_operand:SI 2 "general_operand" "g") (const_int 1)))
+; (match_operand:SI 3 "general_operand" "g")))]
; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8"
; "indexd %0,%2,%3")
\f
;; Set, Clear, and Invert bit
+;; See note 1
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(const_int 1))]
""
"sbitd %1,%0")
+;; See note 1
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g")
(const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(const_int 0))]
""
"cbitd %1,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "+g")
(xor:SI (ashift:SI (const_int 1)
- (match_operand:SI 1 "general_operand" "rmn"))
+ (match_operand:SI 1 "general_operand" "g"))
(match_dup 0)))]
""
"ibitd %1,%0")
+;; See note 1
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=g")
(xor:QI (subreg:QI
(ashift:SI (const_int 1)
- (match_operand:QI 1 "general_operand" "rmn")) 0)
+ (match_operand:QI 1 "general_operand" "g")) 0)
(match_dup 0)))]
""
"ibitb %1,%0")
(minus:SI (match_dup 0)
(match_dup 1)))]
"INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8"
- "acbd %$%n1,%0,%l2")
+ "acbd %n1,%0,%l2")
(define_insn ""
[(set (pc)
"absf %1,%0")
(define_insn "absdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm<")
- (abs:DF (match_operand:DF 1 "general_operand" "fmF")))]
+ [(set (match_operand:DF 0 "general_operand" "=lm<")
+ (abs:DF (match_operand:DF 1 "general_operand" "lmF")))]
"TARGET_32081"
"absl %1,%0")
+;; See note 1
(define_insn "abssi2"
[(set (match_operand:SI 0 "general_operand" "=g<")
- (abs:SI (match_operand:SI 1 "general_operand" "rmn")))]
+ (abs:SI (match_operand:SI 1 "general_operand" "g")))]
""
"absd %1,%0")
;; Speed up stack adjust followed by a HI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(match_operand:HI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzwd %1,tos\", operands);
;; Speed up stack adjust followed by a zero_extend:HI(QI) fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(zero_extend:HI (match_operand:QI 1 "general_operand" "g")))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzbd %1,tos\", operands);
;; Speed up stack adjust followed by a sign_extend:HI(QI) fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -2)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -2)))
(set (match_operand:HI 0 "push_operand" "=m")
(sign_extend:HI (match_operand:QI 1 "general_operand" "g")))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movxbd %1,tos\", operands);
;; Speed up stack adjust followed by a QI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int -3)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int -3)))
(set (match_operand:QI 0 "push_operand" "=m")
(match_operand:QI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,tos\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,tos\"),
operands);
else
output_asm_insn (\"movzbd %1,tos\", operands);
;; Speed up stack adjust followed by a SI fixedpoint push.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 4)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 4)))
(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "g"))]
"! reg_mentioned_p (stack_pointer_rtx, operands[1])"
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,0(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,0(sp)\"),
operands);
else if (GET_CODE (operands[1]) != REG
&& GET_CODE (operands[1]) != MEM
;; Speed up stack adjust followed by two fullword fixedpoint pushes.
(define_peephole
- [(set (reg:SI 17) (plus:SI (reg:SI 17) (const_int 8)))
+ [(set (reg:SI 25) (plus:SI (reg:SI 25) (const_int 8)))
(set (match_operand:SI 0 "push_operand" "=m")
(match_operand:SI 1 "general_operand" "g"))
(set (match_operand:SI 2 "push_operand" "=m")
"*
{
if (GET_CODE (operands[1]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%$%1,4(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[1]), \"%1,4(sp)\"),
operands);
else if (GET_CODE (operands[1]) != REG
&& GET_CODE (operands[1]) != MEM
output_asm_insn (\"movd %1,4(sp)\", operands);
if (GET_CODE (operands[3]) == CONST_INT)
- output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%$%3,0(sp)\"),
+ output_asm_insn (output_move_dconst (INTVAL (operands[3]), \"%3,0(sp)\"),
operands);
else if (GET_CODE (operands[3]) != REG
&& GET_CODE (operands[3]) != MEM
-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
* System V Options::
* V850 Options::
* ARC Options::
+* NS32K Options::
@end menu
@node M680x0 Options
@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