diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-20 01:06:22 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-20 01:06:22 +0000 |
commit | c482518380683ee38d14024c1e362a0d681cf967 (patch) | |
tree | e69b4f6d3fee3aced20a41f3fdf543fc1c77fb5d /gnu/usr.bin/gcc/config/ns32k | |
parent | 76a62188d0db49c65b696d474c855a799fd96dce (diff) |
FSF GCC version 2.7.2
Diffstat (limited to 'gnu/usr.bin/gcc/config/ns32k')
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/encore.h | 196 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/genix.h | 167 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/merlin.h | 231 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/netbsd.h | 112 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/ns32k.c | 873 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/ns32k.h | 1479 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/ns32k.md | 2758 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/pc532-mach.h | 30 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/pc532-min.h | 41 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/pc532.h | 73 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/sequent.h | 77 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/tek6000.h | 235 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/tek6100.h | 7 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/tek6200.h | 7 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/x-genix | 6 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/xm-genix.h | 9 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/xm-netbsd.h | 10 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/xm-ns32k.h | 42 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/config/ns32k/xm-pc532-min.h | 34 |
19 files changed, 6387 insertions, 0 deletions
diff --git a/gnu/usr.bin/gcc/config/ns32k/encore.h b/gnu/usr.bin/gcc/config/ns32k/encore.h new file mode 100644 index 00000000000..028a6533796 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/encore.h @@ -0,0 +1,196 @@ +/* Definitions of target machine for GNU compiler. ENCORE NS32000 version. + Copyright (C) 1988, 1993 Free Software Foundation, Inc. + Adapted by Robert Brown (brown@harvard.harvard.edu) from the Sequent + version by Michael Tiemann (tiemann@mcc.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#define EXTERNAL_PREFIX '?' +#define IMMEDIATE_PREFIX '$' + +#include "ns32k/ns32k.h" + +#define SDB_DEBUGGING_INFO +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* Cause long-jump assembler to be used, + since otherwise some files fail to be assembled right. */ +#define ASM_SPEC "-j" + +#undef ASM_FILE_START +#undef ASM_GENERATE_INTERNAL_LABEL +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_ASCII +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_LOCAL +#undef CPP_PREDEFINES +#undef FUNCTION_BOUNDARY +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef TARGET_VERSION +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_LABELREF_AS_INT + +#define TARGET_DEFAULT 9 /* 32332 with 32081. */ +#define TARGET_VERSION fprintf (stderr, " (32000, Encore syntax)"); +/* Note Encore does not standardly do -Dencore. */ +/* budd: should have a -ns32332 (or -apc) switch! but no harm for now */ +#define CPP_PREDEFINES "-Dns32000 -Dn16 -Dns16000 -Dns32332 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)" + +/* Ignore certain cpp directives used in header files on sysV. */ +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* The .file command should always begin the output. */ +#define ASM_FILE_START(FILE) \ +output_file_directive ((FILE), main_input_filename) + +#define FUNCTION_BOUNDARY 128 /* speed optimization */ + +/* + * The Encore assembler uses ".align 2" to align on 2-byte boundaries. + */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", 1 << (LOG)) + +/* The Encore assembler doesn't seem to accept the usual second argument + and warns that .align may not work in the text section if optimization + is on. */ +#undef ASM_OUTPUT_ALIGN_CODE +#define ASM_OUTPUT_ALIGN_CODE(FILE) + +/* + * Internal labels are prefixed with a period. + */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*.%s%d", PREFIX, NUM) +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.double .L%d-.LI%d\n", VALUE, REL) + +/* + * Different syntax for integer constants, double constants, and + * uninitialized locals. + */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.double "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_LABELREF_AS_INT(STREAM, NAME) \ +do { \ + fprintf (STREAM, "\t.double\t"); \ + ASM_OUTPUT_LABELREF (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} while (0) + + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0f%.20e\n", (VALUE)) + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.bss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (ROUNDED))) + + /* + * Encore assembler can't handle huge string constants like the one in + * gcc.c. If the default routine in varasm.c were more conservative, this + * code could be eliminated. It starts a new .ascii directive every 40 + * characters. + */ + +#define ASM_OUTPUT_ASCII(file, p, size) \ +do { \ + int i; \ + for (i = 0; i < (size); i++) \ + { \ + register int c = (p)[i]; \ + if ((i / 40) * 40 == i) \ + if (i == 0) \ + fprintf ((file), "\t.ascii \""); \ + else \ + fprintf ((file), "\"\n\t.ascii \""); \ + if (c == '\"' || c == '\\') \ + putc ('\\', (file)); \ + if (c >= ' ' && c < 0177) \ + putc (c, (file)); \ + else \ + { \ + fprintf ((file), "\\%o", c); \ + if (i < (size) - 1 \ + && (p)[i + 1] >= '0' && (p)[i + 1] <= '9')\ + fprintf ((file), "\"\n\t.ascii \""); \ + } \ + } \ + fprintf ((file), "\"\n"); \ +} while (0) + +/* Modify syntax of jsr instructions. */ +#define CALL_MEMREF_IMPLICIT + +#define NO_ABSOLUTE_PREFIX_IF_SYMBOLIC + +#define PRINT_OPERAND(FILE, X, CODE) print_operand(FILE, X, CODE) + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) + +/* Change the way in which data is allocated and initialized on the + encore so that both private and shared data are supported. Shared data + that is initialized must be contained in the ".shrdata" section + of the program. This is accomplished by defining the SHARED_SECTION_ASM_OP + macro. Share data that is simply allocated, and not initialized must + be prefixed with the ".shrcomm" or ".shrbss" pseudo op, for common or + local data respectively. This is accomplished by redefining the + ASM_OUTPUT_COMMON and ASM_OUTPUT_LOCAL macros. */ + +/* Assembler pseudo-op for shared data segment. */ + +#define SHARED_SECTION_ASM_OP ".shrdata" + +/* This says how to output an assembler line + to define a shared common symbol. */ + +#define ASM_OUTPUT_SHARED_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".shrcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a shared local symbol. */ + +#define ASM_OUTPUT_SHARED_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.shrbss ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d,%d\n", (SIZE), (ROUNDED))) + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr .LP%d,r0\n\tjsr mcount\n", (LABELNO)) + +#define ENCORE_ASM diff --git a/gnu/usr.bin/gcc/config/ns32k/genix.h b/gnu/usr.bin/gcc/config/ns32k/genix.h new file mode 100644 index 00000000000..ac84cfcb90c --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/genix.h @@ -0,0 +1,167 @@ +/* Definitions of target machine for GNU compiler. Genix ns32000 version. + Copyright (C) 1987, 1988, 1994 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ns32k/encore.h" + +/* We don't want the one Encore needs. */ +#undef ASM_SPEC + +/* The following defines override ones in ns32k.h and prevent any attempts + to explicitly or implicitly make references to the SB register in the GCC + generated code. It is necessary to avoid such references under Genix V.3.1 + because this OS doesn't even save/restore the SB on context switches! */ + +#define IS_OK_REG_FOR_BASE_P(X) \ + ( (GET_CODE (X) == REG) && REG_OK_FOR_BASE_P (X) ) + +#undef INDIRECTABLE_1_ADDRESS_P +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_NO_LABEL_P (X) \ + || IS_OK_REG_FOR_BASE_P (X) \ + || (GET_CODE (X) == PLUS \ + && IS_OK_REG_FOR_BASE_P (XEXP (X, 0)) \ + && CONSTANT_ADDRESS_P (XEXP (X, 1)) ) ) + +/* Note that for double indirects, only FP, SP, and SB are allowed + as the inner-most base register. But we are avoiding use of SB. */ + +#undef MEM_REG +#define MEM_REG(X) \ + ( (GET_CODE (X) == REG) \ + && ( (REGNO (X) == FRAME_POINTER_REGNUM) \ + || (REGNO (X) == STACK_POINTER_REGNUM) ) ) + +#undef INDIRECTABLE_2_ADDRESS_P +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || CONSTANT_ADDRESS_NO_LABEL_P (xfoo0))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#undef GO_IF_NONINDEXED_ADDRESS +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == REG) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P(X)) goto ADDR; \ + if (CONSTANT_P(X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* A bug in the GNX 3.X assembler causes references to external symbols to + be mishandled if the symbol is also used as the name of a function-local + variable or as the name of a struct or union field. The problem only + appears when you are also using the -g option so that SDB debugging + directives are also being produced by GCC. In such cases, the assembler + gets the external entity confused with the local entity and addressing + havoc ensues. The solution is to get GCC to produce .global directives + for all external entities which are actually referenced within the current + source file. The following macro does this. */ + +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + ASM_GLOBALIZE_LABEL(FILE,NAME); + +/* Genix wants 0l instead of 0f. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.long 0l%.20e\n", (VALUE)) + +/* A bug in the GNX 3.X linker prevents symbol-table entries with a storage- + class field of C_EFCN (-1) from being accepted. */ + +#ifdef PUT_SDB_EPILOGUE_END +#undef PUT_SDB_EPILOGUE_END +#endif +#define PUT_SDB_EPILOGUE_END(NAME) + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, National syntax)"); + +/* Same as the encore definition except + * Different syntax for double constants. + * Don't output `?' before external regs. + * Output `(sb)' in certain indirect refs. */ + +#error this has not been updated since version 1. +#error it is certainly wrong. + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc ('$', FILE); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + extern int paren_base_reg_printed; \ + fprintf (FILE, "0("); \ + paren_base_reg_printed = 0; \ + output_address (xfoo); \ + if (!paren_base_reg_printed) \ + fprintf (FILE, "(sb)"); \ + putc (')', FILE); \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "@%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0l%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else if (GET_CODE (X) == CONST) \ + output_addr_const (FILE, X); \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} diff --git a/gnu/usr.bin/gcc/config/ns32k/merlin.h b/gnu/usr.bin/gcc/config/ns32k/merlin.h new file mode 100644 index 00000000000..cf5433cc2f4 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/merlin.h @@ -0,0 +1,231 @@ +/* Definitions of target machine for GNU compiler. MERLIN NS32000 version. + Copyright (C) 1990, 1994 Free Software Foundation, Inc. + By Mark Mason (mason@reed.bitnet, pyramid!unify!mason@uunet.uu.net). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Two flags to control how addresses are printed in assembler insns. */ + +#define SEQUENT_ADDRESS_BUG 1 +#define SEQUENT_BASE_REGS + +#include "ns32k/ns32k.h" + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +#define TARGET_DEFAULT 1 + +/* Print subsidiary information on the compiler version in use. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, UTek syntax)"); + +/* These control the C++ compiler somehow. */ +#define FASCIST_ASSEMBLER +#define USE_COLLECT + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Dns32000 -Dns32k -Dns16000 -Dmerlin -Dunix -DUtek -Dbsd \ + -Asystem(unix) -Asystem(bsd) -Acpu(ns32k) -Amachine(ns32k)" + +/* This is how to align the code that follows an unconditional branch. + Don't define it, since it confuses the assembler (we hear). */ + +#undef ASM_OUTPUT_ALIGN_CODE + +/* Assembler pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +/* %$ means print the prefix for an immediate operand. */ + +#ifdef UTEK_ASM +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '$') putc('$', FILE); \ + else if (CODE == '?'); \ + else if (GET_CODE (X) == CONST_INT) \ + fprintf(FILE, "$%d", INTVAL(X)); \ + else if (GET_CODE (X) == REG) \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + else if (GET_CODE (X) == MEM) \ + { \ + rtx xfoo; \ + xfoo = XEXP (X, 0); \ + switch (GET_CODE (xfoo)) \ + { \ + case MEM: \ + if (GET_CODE (XEXP (xfoo, 0)) == REG) \ + if (REGNO (XEXP (xfoo, 0)) == STACK_POINTER_REGNUM) \ + fprintf (FILE, "0(0(sp))"); \ + else fprintf (FILE, "0(0(%s))", \ + reg_names[REGNO (XEXP (xfoo, 0))]); \ + else \ + { \ + if (GET_CODE (XEXP (xfoo, 0)) == SYMBOL_REF \ + || GET_CODE (XEXP (xfoo, 0)) == CONST) \ + { \ + fprintf(FILE, "0("); \ + output_address(xfoo); \ + fprintf(FILE, "(sb))"); \ + } \ + else \ + { \ + fprintf (FILE, "0("); \ + output_address (xfoo); \ + putc (')', FILE); \ + } \ + } \ + break; \ + case REG: \ + fprintf (FILE, "0(%s)", reg_names[REGNO (xfoo)]); \ + break; \ + case PRE_DEC: \ + case POST_INC: \ + fprintf (FILE, "tos"); \ + break; \ + case CONST_INT: \ + fprintf (FILE, "$%d", INTVAL (xfoo)); \ + break; \ + default: \ + output_address (xfoo); \ + break; \ + } \ + } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \ + if (GET_MODE (X) == DFmode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0d%.20e", u.d); } \ + else { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "$0f%.20e", u.d); } \ + else output_addr_const (FILE, X); } + +#undef FUNCTION_PROLOGUE + +/* This differs from the one in ns32k.h in printing a bitmask + rather than a register list in the enter or save instruction. */ + +#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; \ + extern char call_used_regs[]; \ + MAIN_FUNCTION_PROLOGUE; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + *bufp = -1; \ + for (; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + *fbufp = -1; \ + bufp = used_regs_buf; \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tenter "); \ + else if (g_regs_used) \ + fprintf (FILE, "\tsave "); \ + if (frame_pointer_needed || g_regs_used) \ + { \ + char mask = 0; \ + while (*bufp >= 0) \ + mask |= 1 << *bufp++; \ + fprintf (FILE, "$0x%x", (int) mask & 0xff); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, ",%d\n", SIZE); \ + else if (g_regs_used) \ + fprintf (FILE, "\n"); \ + fbufp = used_fregs_buf; \ + while (*fbufp >= 0) \ + { \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + else \ + { \ + fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fbufp += 2; \ + } \ + } \ +} + +#undef FUNCTION_EPILOGUE + +/* This differs from the one in ns32k.h in printing a bitmask + rather than a register list in the exit or restore instruction. */ + +#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; \ + extern char call_used_regs[]; \ + *fbufp++ = -2; \ + for (regno = 8; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; f_regs_used++; \ + } \ + fbufp--; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + while (fbufp > used_fregs_buf) \ + { \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + { \ + fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fbufp -= 2; \ + } \ + else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\texit "); \ + else if (g_regs_used) \ + fprintf (FILE, "\trestore "); \ + if (g_regs_used || frame_pointer_needed) \ + { \ + char mask = 0; \ + \ + while (bufp > used_regs_buf) \ + { \ + /* Utek assembler takes care of reversing this */ \ + mask |= 1 << *--bufp; \ + } \ + fprintf (FILE, "$0x%x\n", (int) mask & 0xff); \ + } \ + if (current_function_pops_args) \ + fprintf (FILE, "\tret %d\n", current_function_pops_args); \ + else fprintf (FILE, "\tret 0\n"); } + +#endif /* UTEK_ASM */ + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) diff --git a/gnu/usr.bin/gcc/config/ns32k/netbsd.h b/gnu/usr.bin/gcc/config/ns32k/netbsd.h new file mode 100644 index 00000000000..53b7e866b13 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/netbsd.h @@ -0,0 +1,112 @@ +/* Configuration for a ns32532 running NetBSD as the target machine. + Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +*/ + +#include <ns32k/ns32k.h> + +/* Compile for the floating point unit & 32532 by default; + Don't assume SB is zero; + Don't use bitfield instructions; */ + +#define TARGET_DEFAULT (1 + 24 + 32 + 64) + +/* 32-bit alignment for efficiency */ + +#undef POINTER_BOUNDARY +#define POINTER_BOUNDARY 32 + +/* 32-bit alignment for efficiency */ + +#undef FUNCTION_BOUNDARY +#define FUNCTION_BOUNDARY 32 + +/* 32532 spec says it can handle any alignment. Rumor from tm-ns32k.h + tells this might not be actually true (but it's for 32032, perhaps + National has fixed the bug for 32532). You might have to change this + if the bug still exists. */ + +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 + +/* Use pc relative addressing whenever possible, + it's more efficient than absolute (ns32k.c) + You have to fix a bug in gas 1.38.1 to make this work with gas, + patch available from jkp@cs.hut.fi. + (NetBSD's gas version has this patch already applied) */ + +#define PC_RELATIVE + +/* Operand of bsr or jsr should be just the address. */ + +#define CALL_MEMREF_IMPLICIT + +/* movd insns may have floating point constant operands. */ + +#define MOVD_FLOAT_OK + +/* Get generic NetBSD definitions. */ +#include <netbsd.h> + +/* 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)" + +/* Make gcc agree with <machine/ansi.h> */ + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ + +#undef PCC_STATIC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 diff --git a/gnu/usr.bin/gcc/config/ns32k/ns32k.c b/gnu/usr.bin/gcc/config/ns32k/ns32k.c new file mode 100644 index 00000000000..045800bb3cb --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/ns32k.c @@ -0,0 +1,873 @@ +/* Subroutines for assembler code output on the NS32000. + Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Some output-actions in ns32k.md need these. */ +#include <stdio.h> +#include "config.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "output.h" +#include "insn-attr.h" + +#ifdef OSF_OS +int ns32k_num_files = 0; +#endif + +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. */ + +int +hard_regno_mode_ok (regno, mode) + int regno; + enum machine_mode mode; +{ + switch (mode) + { + case QImode: + case HImode: + case PSImode: + case SImode: + case PDImode: + case VOIDmode: + case BLKmode: + if (regno < 8 || regno == 16 || regno == 17) + return 1; + else + return 0; + + case DImode: + if (regno < 8 && (regno & 1) == 0) + 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; + } + + /* Used to abort here, but simply saying "no" handles TImode + much better. */ + return 0; +} + +/* ADDRESS_COST calls this. This function is not optimal + for the 32032 & 32332, but it probably is better than + the default. */ + +int +calc_address_cost (operand) + rtx operand; +{ + int i; + int cost = 0; + + if (GET_CODE (operand) == MEM) + cost += 3; + if (GET_CODE (operand) == MULT) + cost += 2; +#if 0 + if (GET_CODE (operand) == REG) + cost += 1; /* not really, but the documentation + says different amount of registers + shouldn't return the same costs */ +#endif + switch (GET_CODE (operand)) + { + case REG: + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + case POST_DEC: + case PRE_DEC: + break; + case MULT: + case MEM: + case PLUS: + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++) + { + cost += calc_address_cost (XEXP (operand, i)); + } + default: + break; + } + return cost; +} + +/* 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, + NO_REGS is returned. */ + +enum reg_class +secondary_reload_class (class, mode, in) + enum reg_class class; + enum machine_mode mode; + rtx in; +{ + int regno = true_regnum (in); + + if (regno >= FIRST_PSEUDO_REGISTER) + regno = -1; + + /* We can place anything into GENERAL_REGS and can put GENERAL_REGS + into anything. */ + if (class == GENERAL_REGS || (regno >= 0 && regno < 8)) + return NO_REGS; + + /* Constants, memory, and FP registers can go into FP registers. */ + if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS)) + return NO_REGS; + +#if 0 /* This isn't strictly true (can't move fp to sp or vice versa), + so it's cleaner to use PREFERRED_RELOAD_CLASS + to make the right things happen. */ + if (regno >= 16 && class == GEN_AND_MEM_REGS) + return NO_REGS; +#endif + + /* Otherwise, we need GENERAL_REGS. */ + return GENERAL_REGS; +} +/* Generate the rtx that comes from an address expression in the md file */ +/* The expression to be build is BASE[INDEX:SCALE]. To recognize this, + scale must be converted from an exponent (from ASHIFT) to a + multiplier (for MULT). */ +rtx +gen_indexed_expr (base, index, scale) + rtx base, index, scale; +{ + rtx addr; + + /* This generates an invalid addressing mode, if BASE is + fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ + if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) + base = gen_rtx (MEM, SImode, base); + addr = gen_rtx (MULT, SImode, index, + gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); + addr = gen_rtx (PLUS, SImode, base, addr); + return addr; +} + +/* Return 1 if OP is a valid operand of mode MODE. This + predicate rejects operands which do not have a mode + (such as CONST_INT which are VOIDmode). */ +int +reg_or_mem_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_MODE (op) == mode + && (GET_CODE (op) == REG + || GET_CODE (op) == SUBREG + || GET_CODE (op) == MEM)); +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) <= 7 + && INTVAL (operands[1]) >= -8) + return "movqd %1,%0"; + return "movd %1,%0"; +} + +char * +output_move_double (operands) + rtx *operands; +{ + enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1; + rtx latehalf[2]; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + optype1 = CNSTOP; + else if (offsettable_memref_p (operands[1])) + optype1 = OFFSOP; + else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + split_double (operands[1], &operands[1], &latehalf[1]); + else + latehalf[1] = operands[1]; + + /* If insn is effectively movd N(sp),tos then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. + Given this, it doesn't matter which half we do "first". */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = latehalf[1]; + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + else if (optype0 == PUSHOP || optype1 == PUSHOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } + + /* If the first move would clobber the source of the second one, + do them in the other order. */ + + /* Overlapping registers. */ + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + { + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Do low-numbered word. */ + return singlemove_string (operands); + } + /* Loading into a register which overlaps a register used in the address. */ + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + load the destination address into the low reg (operands[0]). + Then it works to load latehalf first. */ + rtx xops[2]; + xops[0] = XEXP (operands[1], 0); + xops[1] = operands[0]; + output_asm_insn ("addr %a0,%1", xops); + operands[1] = gen_rtx (MEM, DImode, operands[0]); + latehalf[1] = adj_offsettable_operand (operands[1], 4); + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) + { + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + } + + /* Normal case. Do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + operands[0] = latehalf[0]; + operands[1] = latehalf[1]; + return singlemove_string (operands); +} + +int +check_reg (oper, reg) + rtx oper; + int reg; +{ + register int i; + + if (oper == 0) + return 0; + switch (GET_CODE(oper)) + { + 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); + } + return 0; +} + +/* Returns 1 if OP contains a global symbol reference */ + +int +global_symbolic_reference_mentioned_p (op, f) + rtx op; + int f; +{ + register char *fmt; + register int i; + + if (GET_CODE (op) == SYMBOL_REF) + { + if (! SYMBOL_REF_FLAG (op)) + return 1; + else + return 0; + } + else if (f && GET_CODE (op) != CONST) + return 0; + + 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 (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0)) + return 1; + } + else if (fmt[i] == 'e' + && global_symbolic_reference_mentioned_p (XEXP (op, i), 0)) + return 1; + } + + return 0; +} + + +/* PRINT_OPERAND is defined to call this function, + which is easier to debug than putting all the code in + a macro definition in ns32k.h. */ + +void +print_operand (file, x, code) + FILE *file; + rtx x; + char code; +{ + if (code == '$') + PUT_IMMEDIATE_PREFIX (file); + else if (code == '?') + PUT_EXTERNAL_PREFIX (file); + else if (GET_CODE (x) == REG) + fprintf (file, "%s", reg_names[REGNO (x)]); + else if (GET_CODE (x) == MEM) + { + rtx tmp = XEXP (x, 0); + output_address (XEXP (x, 0)); + } + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) + { + if (GET_MODE (x) == DFmode) + { + union { double d; int i[2]; } u; + u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); + PUT_IMMEDIATE_PREFIX(file); +#ifdef SEQUENT_ASM + /* Sequent likes it's floating point constants as integers */ + fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]); +#else +#ifdef ENCORE_ASM + fprintf (file, "0f%.20e", u.d); +#else + fprintf (file, "0d%.20e", u.d); +#endif +#endif + } + else + { + union { double d; int i[2]; } u; + u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); + PUT_IMMEDIATE_PREFIX (file); +#ifdef SEQUENT_ASM + /* We have no way of winning if we can't get the bits + for a sequent floating point number. */ +#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT + abort (); +#endif + { + union { float f; long l; } uu; + uu.f = u.d; + fprintf (file, "0Fx%08x", uu.l); + } +#else + fprintf (file, "0f%.20e", u.d); +#endif + } + } + else + { +#ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC + if (GET_CODE (x) == CONST_INT) +#endif + PUT_IMMEDIATE_PREFIX (file); + output_addr_const (file, x); + } +} + +/* PRINT_OPERAND_ADDRESS is defined to call this function, + which is easier to debug than putting all the code in + a macro definition in ns32k.h . */ + +/* Completely rewritten to get this to work with Gas for PC532 Mach. + This function didn't work and I just wasn't able (nor very willing) to + figure out how it worked. + 90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */ + +print_operand_address (file, addr) + register FILE *file; + register rtx addr; +{ + static char scales[] = { 'b', 'w', 'd', 0, 'q', }; + rtx offset, base, indexexp, tmp; + int scale; + extern int flag_pic; + + if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC) + { + fprintf (file, "tos"); + return; + } + + offset = NULL; + base = NULL; + indexexp = NULL; + while (addr != NULL) + { + if (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == PLUS) + { + tmp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + tmp = XEXP (addr,0); + addr = XEXP (addr,1); + } + } + else + { + tmp = addr; + addr = NULL; + } + switch (GET_CODE (tmp)) + { + case PLUS: + abort (); + case MEM: + if (base) + { + indexexp = base; + base = tmp; + } + else + base = tmp; + break; + case REG: + if (REGNO (tmp) < 8) + if (base) + { + indexexp = tmp; + } + else + base = tmp; + else + if (base) + { + indexexp = base; + base = tmp; + } + else + base = tmp; + break; + case MULT: + indexexp = tmp; + break; + case SYMBOL_REF: + if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp) + && ! SYMBOL_REF_FLAG (tmp)) + { + if (base) + { + if (indexexp) + abort (); + indexexp = base; + } + base = tmp; + break; + } + case CONST: + if (flag_pic && GET_CODE (tmp) == CONST) + { + rtx sym, off, tmp1; + tmp1 = XEXP (tmp,0); + if (GET_CODE (tmp1) != PLUS) + abort (); + + sym = XEXP (tmp1,0); + if (GET_CODE (sym) != SYMBOL_REF) + { + off = sym; + sym = XEXP (tmp1,1); + } + else + off = XEXP (tmp1,1); + if (GET_CODE (sym) == SYMBOL_REF) + { + if (GET_CODE (off) != CONST_INT) + abort (); + + if (CONSTANT_POOL_ADDRESS_P (sym) + || SYMBOL_REF_FLAG (sym)) + { + SYMBOL_REF_FLAG (tmp) = 1; + } + else + { + if (base) + { + if (indexexp) + abort (); + + indexexp = base; + } + + if (offset != 0) + abort (); + + base = sym; + offset = off; + break; + } + } + } + case CONST_INT: + case LABEL_REF: + if (offset) + offset = gen_rtx (PLUS, SImode, tmp, offset); + else + offset = tmp; + break; + default: + abort (); + } + } + if (! offset) + offset = const0_rtx; + + if (base +#ifndef INDEX_RATHER_THAN_BASE + && (flag_pic || TARGET_HIMEM) + && GET_CODE (base) != SYMBOL_REF + && GET_CODE (offset) != CONST_INT +#else + /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */ +#endif + && !indexexp && GET_CODE (base) == REG + && REG_OK_FOR_INDEX_P (base)) + { + indexexp = base; + base = NULL; + } + + /* now, offset, base and indexexp are set */ +#ifndef BASE_REG_NEEDED + if (! base) + { +#if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC) + if (GET_CODE (offset) == CONST_INT) +#endif + PUT_ABSOLUTE_PREFIX (file); + } +#endif + + output_addr_const (file, offset); + if (base) /* base can be (REG ...) or (MEM ...) */ + switch (GET_CODE (base)) + { + /* now we must output base. Possible alternatives are: + (rN) (REG ...) + (sp) (REG ...) + (fp) (REG ...) + (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output + (disp(fp)) (MEM ...) just before possible [rX:y] + (disp(sp)) (MEM ...) + (disp(sb)) (MEM ...) + */ + case REG: + fprintf (file, "(%s)", reg_names[REGNO (base)]); + break; + case SYMBOL_REF: + if (! flag_pic) + abort (); + + fprintf (file, "("); + output_addr_const (file, base); + fprintf (file, "(sb))"); + break; + case MEM: + addr = XEXP(base,0); + base = NULL; + offset = NULL; + while (addr != NULL) + { + if (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == PLUS) + { + tmp = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + else + { + tmp = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + } + else + { + tmp = addr; + addr = NULL; + } + switch (GET_CODE (tmp)) + { + case REG: + base = tmp; + break; + case CONST: + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + if (offset) + offset = gen_rtx (PLUS, SImode, tmp, offset); + else + offset = tmp; + break; + default: + abort (); + } + } + if (! offset) + offset = const0_rtx; + fprintf (file, "("); + output_addr_const (file, offset); + if (base) + fprintf (file, "(%s)", reg_names[REGNO (base)]); + else if (TARGET_SB) + fprintf (file, "(sb)"); + else + abort (); + fprintf (file, ")"); + break; + default: + abort (); + } +#ifdef PC_RELATIVE + else if (GET_CODE (offset) != CONST_INT) + fprintf (file, "(pc)"); +#ifdef BASE_REG_NEEDED + else if (TARGET_SB) + fprintf (file, "(sb)"); + else + abort (); +#endif +#endif /* PC_RELATIVE */ + + /* now print index if we have one */ + if (indexexp) + { + if (GET_CODE (indexexp) == MULT) + { + scale = INTVAL (XEXP (indexexp, 1)) >> 1; + indexexp = XEXP (indexexp, 0); + } + else + scale = 0; + if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8) + abort (); + +#ifdef UTEK_ASM + fprintf (file, "[%c`%s]", + scales[scale], + reg_names[REGNO (indexexp)]); +#else + fprintf (file, "[%s:%c]", + reg_names[REGNO (indexexp)], + scales[scale]); +#endif + } +} + +/* National 32032 shifting is so bad that we can get + better performance in many common cases by using other + techniques. */ +char * +output_shift_insn (operands) + rtx *operands; +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 3) + if (GET_CODE (operands[0]) == REG) + { + if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + if (operands[2] == const1_rtx) + return "addd %0,%0"; + else if (INTVAL (operands[2]) == 2) + return "addd %0,%0\n\taddd %0,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + if (operands[2] == const1_rtx) + return "movd %1,%0\n\taddd %0,%0"; + } + else if (GET_CODE (operands[1]) == REG) + { + operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); + return "addr %a1,%0"; + } + else if (INTVAL (operands[2]) == 1 + && GET_CODE (operands[1]) == MEM + && rtx_equal_p (operands [0], operands[1])) + { + rtx temp = XEXP (operands[1], 0); + + if (GET_CODE (temp) == REG + || (GET_CODE (temp) == PLUS + && GET_CODE (XEXP (temp, 0)) == REG + && GET_CODE (XEXP (temp, 1)) == CONST_INT)) + return "addd %0,%0"; + } + else return "ashd %2,%0"; + return "ashd %2,%0"; +} + +char * +output_move_dconst (n, s) + int n; + char *s; +{ + static char r[32]; + + if (n > -9 && n < 8) + strcpy (r, "movqd "); + else if (n > 0 && n < 256) + strcpy (r, "movzbd "); + else if (n > 0 && n < 65536) + strcpy (r, "movzwd "); + else if (n < 0 && n > -129) + strcpy (r, "movxbd "); + else if (n < 0 && n > -32769) + strcpy (r, "movxwd "); + else + strcpy (r, "movd "); + strcat (r, s); + return r; +} diff --git a/gnu/usr.bin/gcc/config/ns32k/ns32k.h b/gnu/usr.bin/gcc/config/ns32k/ns32k.h new file mode 100644 index 00000000000..18a01c3573d --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/ns32k.h @@ -0,0 +1,1479 @@ +/* Definitions of target machine for GNU compiler. NS32000 version. + Copyright (C) 1988, 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@cygnus.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Note that some other tm.h files include this one and then override + many of the definitions that relate to assembler syntax. */ + +extern enum reg_class secondary_reload_class(); + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dns32000 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)" + +/* Print subsidiary information on the compiler version in use. */ +#define TARGET_VERSION fprintf (stderr, " (32000, GAS syntax)"); + + +/* ABSOLUTE PREFIX, IMMEDIATE_PREFIX and EXTERNAL_PREFIX can be defined + to cover most NS32k addressing syntax variations. This way we don't + need to redefine long macros in all the tm.h files for just slight + variations in assembler syntax. */ + +#ifndef ABSOLUTE_PREFIX +#define ABSOLUTE_PREFIX '@' +#endif + +#if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX +#define PUT_IMMEDIATE_PREFIX(FILE) putc(IMMEDIATE_PREFIX, FILE) +#else +#define PUT_IMMEDIATE_PREFIX(FILE) +#endif +#if defined(ABSOLUTE_PREFIX) && ABSOLUTE_PREFIX +#define PUT_ABSOLUTE_PREFIX(FILE) putc(ABSOLUTE_PREFIX, FILE) +#else +#define PUT_ABSOLUTE_PREFIX(FILE) +#endif +#if defined(EXTERNAL_PREFIX) && EXTERNAL_PREFIX +#define PUT_EXTERNAL_PREFIX(FILE) putc(EXTERNAL_PREFIX, FILE) +#else +#define PUT_EXTERNAL_PREFIX(FILE) +#endif + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile 32081 insns for floating point (not library calls). */ +#define TARGET_32081 (target_flags & 1) + +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & 2) + +/* Compile passing first two args in regs 0 and 1. */ +#define TARGET_REGPARM (target_flags & 4) + +/* Options to select type of CPU, for better optimization. + The output is correct for any kind of 32000 regardless of these options. */ +#define TARGET_32532 (target_flags & 8) +#define TARGET_32332 (target_flags & 16) + +/* Ok to use the static base register (and presume it's 0) */ +#define TARGET_SB ((target_flags & 32) == 0) +#define TARGET_HIMEM (target_flags & 128) + +/* Compile using bitfield insns. */ +#define TARGET_BITFIELD ((target_flags & 64) == 0) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + 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 \ + { { "32081", 1}, \ + { "soft-float", -1}, \ + { "rtd", 2}, \ + { "nortd", -2}, \ + { "regparm", 4}, \ + { "noregparm", -4}, \ + { "32532", 24}, \ + { "32332", -8}, \ + { "32332", 16}, \ + { "32032", -24}, \ + { "sb", -32}, \ + { "nosb", 32}, \ + { "bitfield", -64}, \ + { "nobitfield", 64}, \ + { "himem", 128}, \ + { "nohimem", -128}, \ + { "", 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. */ + +#define OVERRIDE_OPTIONS \ +{ \ + if (flag_pic || TARGET_HIMEM) target_flags |= 32; \ +} + + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is not true on the ns32k. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the ns32k. */ +#define BYTES_BIG_ENDIAN 0 + +/* Define this if most significant word of a multiword number is lowest + numbered. This is not true on the ns32k. */ +#define WORDS_BIG_ENDIAN 0 + +/* Number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 32000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 32 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 8 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* Set this nonzero if move instructions will actually fail to work + when given unaligned data. National claims that the NS32032 + works without strict alignment, but rumor has it that operands + crossing a page boundary cause unpredictable results. */ +#define STRICT_ALIGNMENT 1 + +/* If bit field type is int, dont let it cross an int, + and give entire struct the alignment of an int. */ +/* Required on the 386 since it doesn't have a full set of bitfield insns. + (There is no signed extv insn.) */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + 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 + +/* 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, \ + 1, 1} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + 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} + +/* 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. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) hard_regno_mode_ok (REGNO, MODE) + +/* 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)) + +/* 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 17 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 16 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 16 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 1 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 2 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + 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 }; + +#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" } + +/* 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 } + +/* 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) + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS GEN_AND_MEM_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 \ + : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + On the ns32k, these letters are used as follows: + + I : Matches integers which are valid shift amounts for scaled indexing. + These are 0, 1, 2, 3 for byte, word, double, and quadword. + Used for matching arithmetic shifts only on 32032 & 32332. + J : Matches integers which fit a "quick" operand. + K : Matches integers 0 to 7 (for inss and exts instructions). + */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((VALUE) < 8 && (VALUE) + 8 >= 0 ? \ + ((C) == 'I' ? (!TARGET_32532 && 0 <= (VALUE) && (VALUE) <= 3) : \ + (C) == 'J' ? (VALUE) <= 7 : \ + (C) == 'K' ? 0 <= (VALUE) : 0) : 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 1 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + +/* We return GENERAL_REGS instead of GEN_AND_MEM_REGS. + The latter offers no real additional possibilities + 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) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* 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. */ +#define PUSH_ROUNDING(BYTES) (BYTES) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Value is the number of byte 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 32000, 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. */ + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((TARGET_RTD && TREE_CODE (FUNTYPE) != IDENTIFIER_NODE \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) \ + ? (SIZE) : 0) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the 32000 the return value is in R0, + or perhaps in F0 is 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 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. */ + +#define LIBCALL_VALUE(MODE) \ + (((MODE) == DFmode || (MODE) == SFmode) && TARGET_32081 \ + ? gen_rtx (REG, MODE, 8) \ + : gen_rtx (REG, MODE, 0)) + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for a function value. + On the 32000, R0 and F0 are the only registers thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) (((N) & ~8) == 0) + +/* 1 if N is a possible register number for function argument passing. + On the 32000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the ns32k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the ns32k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the 32000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in r0, r1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx (REG, (MODE), (CUM) / 4) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +#ifndef MAIN_FUNCTION_PROLOGUE +#define MAIN_FUNCTION_PROLOGUE +#endif + +/* + * The function prologue for the ns32k is fairly simple. + * If a frame pointer is needed (decided in reload.c ?) then + * we need assembler of the form + * + * # Save the oldframe pointer, set the new frame pointer, make space + * # on the stack and save any general purpose registers necessary + * + * enter [<general purpose regs to save>], <local stack space> + * + * movf fn, tos # Save any floating point registers necessary + * . + * . + * + * If a frame pointer is not needed we need assembler of the form + * + * # Make space on the stack + * + * adjspd <local stack space + 4> + * + * # Save any general purpose registers necessary + * + * save [<general purpose regs to save>] + * + * movf fn, tos # Save any floating point registers necessary + * . + * . + */ +#if defined(IMMEDIATE_PREFIX) && IMMEDIATE_PREFIX +#define ADJSP(FILE, n) \ + fprintf (FILE, "\tadjspd %c%d\n", IMMEDIATE_PREFIX, (n)) +#else +#define ADJSP(FILE, n) \ + fprintf (FILE, "\tadjspd %d\n", (n)) +#endif + +#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; \ + extern char call_used_regs[]; \ + extern int current_function_uses_pic_offset_table, flag_pic; \ + MAIN_FUNCTION_PROLOGUE; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + *bufp = -1; \ + for (; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + { \ + *fbufp++ = regno; \ + } \ + *fbufp = -1; \ + bufp = used_regs_buf; \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tenter ["); \ + else \ + { \ + if (SIZE) \ + ADJSP (FILE, SIZE + 4); \ + if (g_regs_used && g_regs_used > 4) \ + fprintf (FILE, "\tsave ["); \ + else \ + { \ + while (*bufp >= 0) \ + fprintf (FILE, "\tmovd r%d,tos\n", *bufp++); \ + g_regs_used = 0; \ + } \ + } \ + while (*bufp >= 0) \ + { \ + fprintf (FILE, "r%d", *bufp++); \ + if (*bufp >= 0) \ + fputc (',', FILE); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "],%d\n", SIZE); \ + else if (g_regs_used) \ + fprintf (FILE, "]\n"); \ + fbufp = used_fregs_buf; \ + while (*fbufp >= 0) \ + { \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + else \ + { \ + fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fbufp += 2; \ + } \ + } \ + if (flag_pic && current_function_uses_pic_offset_table) \ + { \ + fprintf (FILE, "\tsprd sb,tos\n"); \ + if (TARGET_REGPARM) \ + { \ + fprintf (FILE, "\taddr __GLOBAL_OFFSET_TABLE_(pc),tos\n"); \ + fprintf (FILE, "\tlprd sb,tos\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\taddr __GLOBAL_OFFSET_TABLE_(pc),r0\n"); \ + fprintf (FILE, "\tlprd sb,r0\n"); \ + } \ + } \ +} + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. + + THIS DEFINITION FOR THE 32000 IS A GUESS. IT HAS NOT BEEN TESTED. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\taddr LP%d,r0\n\tbsr mcount\n", (LABELNO)) + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. + + We use 0, because using 1 requires hair in FUNCTION_EPILOGUE + that is worse than the stack adjust we could save. */ + +/* #define EXIT_IGNORE_STACK 1 */ + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer, + if EXIT_IGNORE_STACK is nonzero. That doesn't apply here. + + If a frame pointer is needed (decided in reload.c ?) then + we need assembler of the form + + movf tos, fn # Restore any saved floating point registers + . + . + + # Restore any saved general purpose registers, restore the stack + # pointer from the frame pointer, restore the old frame pointer. + exit [<general purpose regs to save>] + + If a frame pointer is not needed we need assembler of the form + # Restore any general purpose registers saved + + movf tos, fn # Restore any saved floating point registers + . + . + . + restore [<general purpose regs to save>] + + # reclaim space allocated on stack + + adjspd <-(local stack space + 4)> */ + + +#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; \ + 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++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) \ + { \ + *fbufp++ = regno; f_regs_used++; \ + } \ + fbufp--; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + while (fbufp > used_fregs_buf) \ + { \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + { \ + fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fbufp -= 2; \ + } \ + else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\texit ["); \ + else \ + { \ + if (g_regs_used && g_regs_used > 4) \ + fprintf (FILE, "\trestore ["); \ + else \ + { \ + while (bufp > used_regs_buf) \ + fprintf (FILE, "\tmovd tos,r%d\n", *--bufp); \ + g_regs_used = 0; \ + } \ + } \ + while (bufp > used_regs_buf) \ + { \ + fprintf (FILE, "r%d", *--bufp); \ + if (bufp > used_regs_buf) \ + fputc (',', FILE); \ + } \ + if (g_regs_used || frame_pointer_needed) \ + fprintf (FILE, "]\n"); \ + if (SIZE && !frame_pointer_needed) \ + ADJSP (FILE, -(SIZE + 4)); \ + if (current_function_pops_args) \ + fprintf (FILE, "\tret %d\n", current_function_pops_args); \ + else fprintf (FILE, "\tret 0\n"); } + +/* Store in the variable DEPTH the initial difference between the + frame pointer reg contents and the stack pointer reg contents, + as of the start of the function body. This depends on the layout + of the fixed parts of the stack frame and on how registers are saved. */ + +#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \ +{ \ + int regno; \ + int offset = -4; \ + extern int current_function_uses_pic_offset_table, flag_pic; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + if (flag_pic && current_function_uses_pic_offset_table) \ + offset += 4; \ + (DEPTH) = (offset + get_frame_size () \ + + (get_frame_size () == 0 ? 0 : 4)); \ +} + + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. */ + +/* On the 32k, the trampoline looks like this: + addr 0(pc),r2 + jump @__trampoline + .int STATIC + .int FUNCTION +Doing trampolines with a library assist function is easier than figuring +out how to do stores to memory in reverse byte order (the way immediate +operands on the 32k are stored). */ + +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf (FILE, "\taddr 0(pc),r2\n" ); \ + fprintf (FILE, "\tjump " ); \ + PUT_ABSOLUTE_PREFIX (FILE); \ + fprintf (FILE, "__trampoline\n" ); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ +} + +/* Length in units of the trampoline for entering a nested function. */ + +#define TRAMPOLINE_SIZE 20 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ + +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 12)), CXT); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 16)), FNADDR); \ +} + +/* This is the library routine that is used + to transfer control from the trampoline + to the actual nested function. */ + +/* The function name __transfer_from_trampoline is not actually used. + The function definition just permits use of "asm with operands" + (though the operand list is empty). */ +#define TRANSFER_FROM_TRAMPOLINE \ +void \ +__transfer_from_trampoline () \ +{ \ + asm (".globl __trampoline"); \ + asm ("__trampoline:"); \ + asm ("movd 16(r2),tos"); \ + asm ("movd 12(r2),r1"); \ + asm ("ret 0"); \ +} + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT */ +/* #define HAVE_POST_DECREMENT */ + +/* #define HAVE_PRE_DECREMENT */ +/* #define HAVE_PRE_INCREMENT */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +/* 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) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +((REGNO) < 8 || (unsigned)reg_renumber[REGNO] < 8 \ + || (REGNO) == FRAME_POINTER_REGNUM || (REGNO) == STACK_POINTER_REGNUM) + +#define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* 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. */ + +#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))) + +#define CONSTANT_ADDRESS_NO_LABEL_P(X) \ + (GET_CODE (X) == CONST_INT \ + && ((unsigned)INTVAL (X) >= 0xe0000000 \ + || (unsigned)INTVAL (X) < 0x20000000)) + +/* 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, + NO_REGS is returned. */ + +#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \ + secondary_reload_class (CLASS, MODE, IN) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* 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) +/* 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) +/* Nonzero if X is a floating point reg or a pseudo reg. */ + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +/* 1 if X is an address that we could indirect through. */ +/***** NOTE ***** There is a bug in the Sequent assembler which fails + to fixup addressing information for symbols used as offsets + from registers which are not FP or SP (or SB or PC). This + makes _x(fp) valid, while _x(r0) is invalid. */ + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + (CONSTANT_ADDRESS_P (X) \ + || (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == PLUS \ + && GET_CODE (XEXP (X, 0)) == REG \ + && REG_OK_FOR_BASE_P (XEXP (X, 0)) \ + && ((flag_pic || TARGET_HIMEM) ? \ + CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1)) \ + : \ + CONSTANT_ADDRESS_P (XEXP (X, 1))) \ + && (GET_CODE (X) != CONST_INT || NS32K_DISPLACEMENT_P (INTVAL (X))))) + +/* 1 if integer I will fit in a 4 byte displacement field. + Strictly speaking, we can't be sure that a symbol will fit this range. + But, in practice, it always will. */ + +/* idall@eleceng.adelaide.edu.au says that the 32016 and 32032 + can handle the full range of displacements--it is only the addresses + that have a limited range. So the following was deleted: + (((i) <= 16777215 && (i) >= -16777216) + || ((TARGET_32532 || TARGET_32332) && ...)) */ +#define NS32K_DISPLACEMENT_P(i) \ + ((i) < (1 << 29) && (i) >= - (1 << 29)) + +/* Check for frame pointer or stack pointer. */ +#define MEM_REG(X) \ + (GET_CODE (X) == REG && (REGNO (X) ^ 16) < 2) + +/* A memory ref whose address is the FP or SP, with optional integer offset, + or (on certain machines) a constant address. */ +#define INDIRECTABLE_2_ADDRESS_P(X) \ + (GET_CODE (X) == MEM \ + && (((xfoo0 = XEXP (X, 0), MEM_REG (xfoo0)) \ + || (GET_CODE (xfoo0) == PLUS \ + && MEM_REG (XEXP (xfoo0, 0)) \ + && CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfoo0, 1)))) \ + || (TARGET_SB && CONSTANT_ADDRESS_P (xfoo0)))) + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ register rtx xfoob = (X); \ + if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (GET_CODE (X) == PLUS) \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (X, 1))) \ + if (INDIRECTABLE_2_ADDRESS_P (XEXP (X, 0))) \ + goto ADDR; \ +} + +/* Go to ADDR if X is a valid address not using indexing. + (This much is the easy part.) */ +#define GO_IF_INDEXING(X, MODE, ADDR) \ +{ register rtx xfoob = (X); \ + if (GET_CODE (xfoob) == PLUS && INDEX_TERM_P (XEXP (xfoob, 0), MODE)) \ + GO_IF_INDEXABLE_ADDRESS (XEXP (xfoob, 1), ADDR); \ + if (GET_CODE (xfoob) == PLUS && INDEX_TERM_P (XEXP (xfoob, 1), MODE)) \ + GO_IF_INDEXABLE_ADDRESS (XEXP (xfoob, 0), ADDR); } \ + +#define GO_IF_INDEXABLE_ADDRESS(X, ADDR) \ +{ if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) goto ADDR; \ + if (INDIRECTABLE_2_ADDRESS_P (X)) goto ADDR; \ + if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; \ +} + +/* 1 if PROD is either a reg times size of mode MODE + or just a reg, if MODE is just one byte. Actually, on the ns32k, + since the index mode is independent of the operand size, + we can match more stuff... + + This macro's expansion uses the temporary variables xfoo0, xfoo1 + and xfoo2 that must be declared in the surrounding context. */ +#define INDEX_TERM_P(PROD, MODE) \ +((GET_CODE (PROD) == REG && REG_OK_FOR_INDEX_P (PROD)) \ + || (GET_CODE (PROD) == MULT \ + && (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \ + (GET_CODE (xfoo1) == CONST_INT \ + && GET_CODE (xfoo0) == REG \ + && FITS_INDEX_RANGE (INTVAL (xfoo1)) \ + && REG_OK_FOR_INDEX_P (xfoo0))))) + +#define FITS_INDEX_RANGE(X) \ + ((xfoo2 = (unsigned)(X)-1), \ + ((xfoo2 < 4 && xfoo2 != 2) || xfoo2 == 7)) + +/* Note that xfoo0, xfoo1, xfoo2 are used in some of the submacros above. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ register rtx xfooy, xfoo0, xfoo1; \ + unsigned xfoo2; \ + extern int current_function_uses_pic_offset_table, flag_pic; \ + xfooy = X; \ + if (flag_pic && ! current_function_uses_pic_offset_table \ + && global_symbolic_reference_mentioned_p (X, 1)) \ + current_function_uses_pic_offset_table = 1; \ + GO_IF_NONINDEXED_ADDRESS (xfooy, ADDR); \ + if (GET_CODE (xfooy) == PLUS) \ + { \ + if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfooy, 1)) \ + && GET_CODE (XEXP (xfooy, 0)) == PLUS) \ + xfooy = XEXP (xfooy, 0); \ + else if (CONSTANT_ADDRESS_NO_LABEL_P (XEXP (xfooy, 0)) \ + && GET_CODE (XEXP (xfooy, 1)) == PLUS) \ + xfooy = XEXP (xfooy, 1); \ + GO_IF_INDEXING (xfooy, MODE, ADDR); \ + } \ + else if (INDEX_TERM_P (xfooy, MODE)) \ + goto ADDR; \ + else if (GET_CODE (xfooy) == PRE_DEC) \ + if (REGNO (XEXP (xfooy, 0)) == STACK_POINTER_REGNUM) goto ADDR; \ + else abort (); \ +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the ns32k, we do nothing */ + +#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 + 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))? \ + (current_function_uses_pic_offset_table = 1):0 \ + ), 1) + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + On the ns32k, if using PIC, mark a SYMBOL_REF for a non-global + symbol or a code symbol. These symbols are referenced via pc + and not via sb. */ + +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + extern int flag_pic; \ + if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + } \ +while (0) + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the ns32k, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + { if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) \ + goto LABEL;} + +/* 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 + all programs. */ +#define CASE_VECTOR_MODE SImode + +/* Define this if the tablejump instruction expects the table + to contain offsets from the address of the table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +/* #define SLOW_ZERO_EXTEND */ + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of address ADDRESS. */ + +#define ADDRESS_COST(RTX) calc_address_cost (RTX) + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ + case CONST_INT: \ + if (INTVAL (RTX) <= 7 && INTVAL (RTX) >= -8) return 0; \ + if (INTVAL (RTX) < 0x2000 && INTVAL (RTX) >= -0x2000) \ + return 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* This bit means that what ought to be in the Z bit + should be tested in the F bit. */ +#define CC_Z_IN_F 04000 + +/* This bit means that what ought to be in the Z bit + is complemented in the F bit. */ +#define CC_Z_IN_NOT_F 010000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ +{ if (GET_CODE (EXP) == SET) \ + { if (GET_CODE (SET_DEST (EXP)) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (EXP); \ + cc_status.value2 = SET_SRC (EXP); \ + } \ + else if (GET_CODE (SET_SRC (EXP)) == CALL) \ + { CC_STATUS_INIT; } \ + else if (GET_CODE (SET_DEST (EXP)) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (EXP), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (EXP)) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == PARALLEL \ + && GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \ + { if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == CC0) \ + { cc_status.flags = 0; \ + cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \ + cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == REG) \ + { if (cc_status.value1 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value1)) \ + cc_status.value1 = 0; \ + if (cc_status.value2 \ + && reg_overlap_mentioned_p (SET_DEST (XVECEXP (EXP, 0, 0)), cc_status.value2)) \ + cc_status.value2 = 0; \ + } \ + else if (GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) == MEM) \ + { CC_STATUS_INIT; } \ + } \ + else if (GET_CODE (EXP) == CALL) \ + { /* all bets are off */ CC_STATUS_INIT; } \ + else { /* nothing happens? CC_STATUS_INIT; */} \ + if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \ + && cc_status.value2 \ + && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \ + abort (); \ +} + +/* 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 */ + +#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 OUTPUT_JUMP(NORMAL, NO_OV) \ +{ if (cc_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Dividing the output into sections */ + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Define the output Assembly Language */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output of Data */ + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\t.double 0d%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\t.float 0f%.20e\n", (VALUE)) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* 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) + +/* 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_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovd %s,tos\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from 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. */ + +#ifndef COLLECT +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) +#else +#define ASM_OUTPUT_LABEL(STREAM,NAME) \ +do { \ + fprintf (STREAM, "%s:\n", NAME); \ +} while (0) +#endif + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#ifndef COLLECT +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) +#else +#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ +do { \ + fprintf (STREAM, "\t.globl\t%s\n", NAME); \ +} while (0) +#endif + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#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 ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%d", PREFIX, NUM) + +/* This is how to align the code that follows an unconditional branch. + Note that 0xa2 is a no-op. */ + +#define ASM_OUTPUT_ALIGN_CODE(FILE) \ + fprintf (FILE, "\t.align 2,0xa2\n") + +/* This is how to output an element of a case-vector that is absolute. + (The ns32k does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ +/* ** Notice that the second element is LI format! */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \ + fprintf (FILE, "\t.long L%d-LI%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print an instruction operand X on file FILE. + CODE is the code from the %-spec that requested printing this operand; + if `%z3' was used to print operand 3, then CODE is 'z'. */ + +/* %$ means print the prefix for an immediate operand. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '$' || (CODE) == '?') + +#define PRINT_OPERAND(FILE, X, CODE) print_operand(FILE, X, CODE) + +/* Print a memory operand whose address is X, on file FILE. */ + +#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 (); + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gnu/usr.bin/gcc/config/ns32k/ns32k.md b/gnu/usr.bin/gcc/config/ns32k/ns32k.md new file mode 100644 index 00000000000..679ca9a6ca5 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/ns32k.md @@ -0,0 +1,2758 @@ +;;- Machine description for GNU compiler, ns32000 Version +;; Copyright (C) 1988, 1994 Free Software Foundation, Inc. +;; Contributed by Michael Tiemann (tiemann@cygnus.com) + +;; This file is part of GNU CC. + +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + + +; BUGS: +;; Insert no-op between an insn with memory read-write operands +;; following by a scale-indexing operation. +;; The Sequent assembler does not allow addresses to be used +;; except in insns which explicitly compute an effective address. +;; I.e., one cannot say "cmpd _p,@_x" +;; Implement unsigned multiplication?? + +;;- Instruction patterns. When multiple patterns apply, +;;- the first one in the file is chosen. +;;- +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;;- +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;; 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. + +(define_insn "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqd %1,%0\"; }") + +(define_insn "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqw %1,%0\"; }") + +(define_insn "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "g"))] + "" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = const0_rtx; + return \"cmpqb %1,%0\"; }") + +(define_insn "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = CONST0_RTX (DFmode); + return \"cmpl %1,%0\"; }") + +(define_insn "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fmF"))] + "TARGET_32081" + "* +{ cc_status.flags |= CC_REVERSED; + operands[1] = CONST0_RTX (SFmode); + return \"cmpf %1,%0\"; }") + +(define_insn "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "rmn") + (match_operand:SI 1 "general_operand" "rmn")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + return \"cmpqd %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + int i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + return \"cmpqd %0,%1\"; + } + return \"cmpd %0,%1\"; +}") + +(define_insn "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "g") + (match_operand:HI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + short i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqw %0,%1\"; + } + } + return \"cmpw %0,%1\"; +}") + +(define_insn "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "g") + (match_operand:QI 1 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + char i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + cc_status.flags |= CC_REVERSED; + if (INTVAL (operands[1]) > 7) + operands[1] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %1,%0\"; + } + } + cc_status.flags &= ~CC_REVERSED; + if (GET_CODE (operands[0]) == CONST_INT) + { + char i = INTVAL (operands[0]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[0]) > 7) + operands[0] = gen_rtx(CONST_INT, VOIDmode, i); + return \"cmpqb %0,%1\"; + } + } + return \"cmpb %0,%1\"; +}") + +(define_insn "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "fmF") + (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpl %0,%1") + +(define_insn "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "fmF") + (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "cmpf %0,%1") + +(define_insn "movdf" + [(set (match_operand:DF 0 "general_operand" "=fg<") + (match_operand:DF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "movsf" + [(set (match_operand:SF 0 "general_operand" "=fg<") + (match_operand:SF 1 "general_operand" "fFg"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } +#if 0 /* Someone suggested this for the Sequent. Is it needed? */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movf %1,%0\"; +#endif +/* There was a #if 0 around this, but that was erroneous + for many machines -- rms. */ +#ifndef MOVD_FLOAT_OK + /* GAS understands floating constants in ordinary movd instructions + but other assemblers might object. */ + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + union {int i[2]; float f; double d;} convrt; + convrt.i[0] = CONST_DOUBLE_LOW (operands[1]); + convrt.i[1] = CONST_DOUBLE_HIGH (operands[1]); + convrt.f = convrt.d; + + /* Is there a better machine-independent way to to this? */ + operands[1] = gen_rtx (CONST_INT, VOIDmode, convrt.i[0]); + return \"movd %1,%0\"; + } +#endif + else return \"movd %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:TI 0 "memory_operand" "=m") + (match_operand:TI 1 "memory_operand" "m"))] + "" + "movmd %1,%0,4") + +(define_insn "movdi" + [(set (match_operand:DI 0 "general_operand" "=g<,*f,g") + (match_operand:DI 1 "general_operand" "gF,g,*f"))] + "" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) + return \"movl %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"movd %1,tos\", xoperands); + output_asm_insn (\"movd %1,tos\", operands); + return \"movl tos,%0\"; + } + return \"movl %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"movl %1,tos\;movd tos,%0\", operands); + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"movd tos,%0\"; + } + else + return \"movl %1,%0\"; + } + return output_move_double (operands); +}") + +;; This special case must precede movsi. +(define_insn "" + [(set (reg:SI 17) + (match_operand:SI 0 "general_operand" "rmn"))] + "" + "lprd sp,%0") + +(define_insn "movsi" + [(set (match_operand:SI 0 "general_operand" "=g<,g<,*f,g,x") + (match_operand:SI 1 "general_operand" "g,?xy,g,*f,rmn"))] + "" + "* +{ + extern int flag_pic; \ + + if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movd %1,tos\;movf tos,%0\"; + else + return \"movf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } + if (GET_CODE (operands[0]) == REG + && REGNO (operands[0]) == FRAME_POINTER_REGNUM) + return \"lprd fp,%1\"; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] + = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (operands[1])); + if (GET_CODE (operands[1]) == CONST_INT) + { + int i = INTVAL (operands[1]); + if (! TARGET_32532) + { + if (i <= 7 && i >= -8) + return \"movqd %1,%0\"; + if (i <= 0x1fffffff && i >= -0x20000000) +#if defined (GNX_V3) || defined (UTEK_ASM) + return \"addr %c1,%0\"; +#else + return \"addr @%c1,%0\"; +#endif + return \"movd %$%1,%0\"; + } + else + return output_move_dconst(i, \"%$%1,%0\"); + } + else if (GET_CODE (operands[1]) == CONST && ! flag_pic) + { + /* Must contain symbols so we don`t know how big it is. In + * that case addr might lead to overflow. For PIC symbolic + * address loads always have to be done with addr. + */ + return \"movd %$%1,%0\"; + } + else if (GET_CODE (operands[1]) == REG) + { + if (REGNO (operands[1]) < 16) + return \"movd %1,%0\"; + else if (REGNO (operands[1]) == FRAME_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd fp,%0\"; + else + return \"addr 0(fp),%0\" ; + } + else if (REGNO (operands[1]) == STACK_POINTER_REGNUM) + { + if (GET_CODE(operands[0]) == REG) + return \"sprd sp,%0\"; + else + return \"addr 0(sp),%0\" ; + } + else abort (); + } + else if (GET_CODE (operands[1]) == MEM) + return \"movd %1,%0\"; + + /* Check if this effective address can be + calculated faster by pulling it apart. */ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +(define_insn "movhi" + [(set (match_operand:HI 0 "general_operand" "=g<,*f,g") + (match_operand:HI 1 "general_operand" "g,g,*f"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + short i = INTVAL (operands[1]); + if (i <= 7 && i >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, i); + return \"movqw %1,%0\"; + } + return \"movw %1,%0\"; + } + else if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movwf %1,tos\;movf tos,%0\"; + else + return \"movwf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } + else + return \"movw %1,%0\"; +}") + +(define_insn "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+r")) + (match_operand:HI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) <= 7 && INTVAL(operands[1]) >= -8) + return \"movqw %1,%0\"; + return \"movw %1,%0\"; +}") + +(define_insn "movqi" + [(set (match_operand:QI 0 "general_operand" "=g<,*f,g") + (match_operand:QI 1 "general_operand" "g,g,*f"))] + "" + "* +{ if (GET_CODE (operands[1]) == CONST_INT) + { + char char_val = (char)INTVAL (operands[1]); + if (char_val <= 7 && char_val >= -8) + { + if (INTVAL (operands[1]) > 7) + operands[1] = + gen_rtx (CONST_INT, VOIDmode, char_val); + return \"movqb %1,%0\"; + } + return \"movb %1,%0\"; + } + else if (FP_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 8) + return \"movbf %1,tos\;movf tos,%0\"; + else + return \"movbf %1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + return \"movf %1,tos\;movd tos,%0\"; + return \"movf %1,%0\"; + } + else + return \"movb %1,%0\"; +}") + +(define_insn "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+r")) + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL(operands[1]) < 8 && INTVAL(operands[1]) > -9) + return \"movqb %1,%0\"; + return \"movb %1,%0\"; +}") + +;; This is here to accept 4 arguments and pass the first 3 along +;; to the movstrsi1 pattern that really does the work. +(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 "" "")] + "" + " + emit_insn (gen_movstrsi1 (operands[0], operands[1], operands[2])); + DONE; +") + +;; 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))] + "" + "* +{ + 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); + +#ifdef UTEK_ASM + if (GET_CODE (operands[2]) == CONST_INT && (INTVAL (operands[2]) & 0x3) == 0) + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, 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_rtx (CONST_INT, VOIDmode, 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 +}") + +;; Extension and truncation insns. +;; Those for integer source operand +;; are ordered widest source type first. + +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:SI 1 "nonimmediate_operand" "rmn")))] + "" + "movb %1,%0") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (truncate:HI (match_operand:SI 1 "nonimmediate_operand" "rmn")))] + "" + "movw %1,%0") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (truncate:QI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movb %1,%0") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movxwd %1,%0") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movxbw %1,%0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movxbd %1,%0") + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (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")))] + "TARGET_32081" + "movlf %1,%0") + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "g")))] + "" + "movzwd %1,%0") + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbw %1,%0") + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "g")))] + "" + "movzbd %1,%0") + +;; Fix-to-float conversion insns. +;; Note that the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +;; Rumor has it that the National part does not correctly convert +;; constant ints to floats. This conversion is therefore disabled. +;; A register must be used to perform the conversion. + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdf %1,%0") + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:SI 1 "general_operand" "rm")))] + "TARGET_32081" + "movdl %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwf %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (float:DF (match_operand:HI 1 "general_operand" "rm")))] + "TARGET_32081" + "movwl %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (float:SF (match_operand:QI 1 "general_operand" "rm")))] + "TARGET_32081" + "movbf %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<") +; (float:DF (match_operand:QI 1 "general_operand" "rm")))] +; "TARGET_32081" +; "movbl %1,%0") + +;; Float-to-fix conversion insns. +;; The sequent compiler always generates "trunc" insns. + +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] + "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"))))] + "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"))))] + "TARGET_32081" + "truncld %1,%0") + +;; Unsigned + +(define_insn "fixunssfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (unsigned_fix:QI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fixunssfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (unsigned_fix:HI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fixunssfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (unsigned_fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] + "TARGET_32081" + "truncfd %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"))))] + "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"))))] + "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"))))] + "TARGET_32081" + "truncld %1,%0") + +;;; These are not yet used by GCC +(define_insn "fix_truncsfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfb %1,%0") + +(define_insn "fix_truncsfhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (fix:HI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfw %1,%0") + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (fix:SI (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_32081" + "truncfd %1,%0") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (fix:QI (match_operand:DF 1 "general_operand" "fm")))] + "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")))] + "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")))] + "TARGET_32081" + "truncld %1,%0") + +;;- All kinds of add instructions. + +(define_insn "adddf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addl %2,%0") + + +(define_insn "addsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "addf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (plus:SI (reg:SI 17) + (match_operand:SI 0 "immediate_operand" "i")))] + "GET_CODE (operands[0]) == CONST_INT" + "* +{ +#ifndef SEQUENT_ADJUST_STACK + if (TARGET_32532) + if (INTVAL (operands[0]) == 8) + return \"cmpd tos,tos\"; + if (TARGET_32532 || TARGET_32332) + if (INTVAL (operands[0]) == 4) + return \"cmpqd %$0,tos\"; +#endif + if (! TARGET_32532) + { + if (INTVAL (operands[0]) < 64 && INTVAL (operands[0]) > -64) + return \"adjspb %$%n0\"; + else if (INTVAL (operands[0]) < 8192 && INTVAL (operands[0]) >= -8192) + return \"adjspw %$%n0\"; + } + return \"adjspd %$%n0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (plus:SI (reg:SI 16) + (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) + (match_operand:SI 1 "immediate_operand" "i")))] + "GET_CODE (operands[1]) == CONST_INT" + "addr %c1(sp),%0") + +(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")))] + "" + "* +{ + if (which_alternative == 1) + { + int i = INTVAL (operands[2]); + if (NS32K_DISPLACEMENT_P (i)) + return \"addr %c2(%1),%0\"; + else + return \"movd %1,%0\;addd %2,%0\"; + } + 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) + return \"addr %c2(%0),%0\"; + } + return \"addd %2,%0\"; +}") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (plus:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqw %2,%0\"; + } + return \"addw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (plus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqw %2,%0\"; + return \"addw %2,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (plus:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + if (i <= 7 && i >= -8) + return \"addqb %2,%0\"; + } + return \"addb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (plus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-9 && INTVAL(operands[1]) < 8) + return \"addqb %2,%0\"; + return \"addb %2,%0\"; +}") + +;;- All kinds of subtract instructions. + +(define_insn "subdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subl %2,%0") + +(define_insn "subsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "subf %2,%0") + +(define_insn "" + [(set (reg:SI 17) + (minus:SI (reg:SI 17) + (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\"; +}") + +(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")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqd %$%n2,%0\"; + } + return \"subd %2,%0\"; +}") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqw %$%n2,%0\"; + } + return \"subw %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "=r")) + (minus:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqw %$%n2,%0\"; + return \"subw %2,%0\"; +}") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + int i = INTVAL (operands[2]); + + if (i <= 8 && i >= -7) + return \"addqb %$%n2,%0\"; + } + return \"subb %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "=r")) + (minus:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >-8 && INTVAL(operands[1]) < 9) + return \"addqb %$%n2,%0\"; + return \"subb %2,%0\"; +}") + +;;- Multiply instructions. + +(define_insn "muldf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mull %2,%0") + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "mulf %2,%0") + +(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")))] + "" + "muld %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "mulw %2,%0") + +(define_insn "mulqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mult:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "mulb %2,%0") + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "general_operand" "=g") + (mult:DI (zero_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "0")) + (zero_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "rmn"))))] + "" + "meid %2,%0") + +;;- Divide instructions. + +(define_insn "divdf3" + [(set (match_operand:DF 0 "general_operand" "=fm") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divl %2,%0") + +(define_insn "divsf3" + [(set (match_operand:SF 0 "general_operand" "=fm") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fmF")))] + "TARGET_32081" + "divf %2,%0") + +(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")))] + "" + "quod %2,%0") + +(define_insn "divhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "quow %2,%0") + +(define_insn "divqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (div:QI (match_operand:QI 1 "general_operand" "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\"; +}") + +;; Remainder instructions. + +(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")))] + "" + "remd %2,%0") + +(define_insn "modhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (mod:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "remw %2,%0") + +(define_insn "modqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (mod:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "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") + +;;- Logical Instructions: AND + +(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")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if ((INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + if ((INTVAL (operands[2]) | 0xffff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffff0000) + return \"movqw %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xffff); + return \"andw %2,%0\"; + } + } + } + return \"andd %2,%0\"; +}") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xff) == 0xffffffff) + { + if (INTVAL (operands[2]) == 0xffffff00) + return \"movqb %$0,%0\"; + else + { + operands[2] = gen_rtx (CONST_INT, VOIDmode, + INTVAL (operands[2]) & 0xff); + return \"andb %2,%0\"; + } + } + return \"andw %2,%0\"; +}") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "andb %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (and:SI (not:SI (match_operand:SI 1 "general_operand" "rmn")) + (match_operand:SI 2 "general_operand" "0")))] + "" + "bicd %1,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (and:HI (not:HI (match_operand:HI 1 "general_operand" "g")) + (match_operand:HI 2 "general_operand" "0")))] + "" + "bicw %1,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (and:QI (not:QI (match_operand:QI 1 "general_operand" "g")) + (match_operand:QI 2 "general_operand" "0")))] + "" + "bicb %1,%0") + +;;- Bit set instructions. + +(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")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"orw %2,%0\"; + } + return \"ord %2,%0\"; +}") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ior:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"orb %2,%0\"; + return \"orw %2,%0\"; +}") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ior:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "orb %2,%0") + +;;- xor instructions. + +(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")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) { + if ((INTVAL (operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + if ((INTVAL (operands[2]) & 0xffff0000) == 0) + return \"xorw %2,%0\"; + } + return \"xord %2,%0\"; +}") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "g")))] + "" + "* +{ + if (GET_CODE(operands[2]) == CONST_INT && + (INTVAL(operands[2]) & 0xffffff00) == 0) + return \"xorb %2,%0\"; + return \"xorw %2,%0\"; +}") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "g")))] + "" + "xorb %2,%0") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (neg:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negl %1,%0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (neg:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "negf %1,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (neg:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "negd %1,%0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (neg:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "negw %1,%0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (neg:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "negb %1,%0") + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (not:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "comd %1,%0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (not:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "comw %1,%0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (not:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "comb %1,%0") + +;; arithmetic left and right shift operations +;; on the 32532 we will always use lshd for arithmetic left shifts, +;; because it is three times faster. Broken programs which +;; use negative shift counts are probably broken differently +;; than elsewhere. + +;; alternative 0 never matches on the 32532 +(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")))] + "" + "* +{ if (TARGET_32532) + return \"lshd %2,%0\"; + else + return output_shift_insn (operands); +}") + +(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")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) == 1) + return \"addw %0,%0\"; + else if (! TARGET_32532 && INTVAL (operands[2]) == 2) + return \"addw %0,%0\;addw %0,%0\"; + } + if (TARGET_32532) + return \"lshw %2,%0\"; + else + return \"ashw %2,%0\"; +}") + +(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")))] + "" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) == 1) + return \"addb %0,%0\"; + else if (! TARGET_32532 && INTVAL (operands[2]) == 2) + return \"addb %0,%0\;addb %0,%0\"; + } + if (TARGET_32532) + return \"lshb %2,%0\"; + else + return \"ashb %2,%0\"; +}") + +;; Arithmetic right shift on the 32k works by negating the shift count. +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "ashd %$%n2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "ashd %2,%0") + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "ashw %$%n2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "ashw %2,%0") + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "ashb %$%n2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "ashb %2,%0") + +;; logical shift instructions + +;; Logical right shift on the 32k works by negating the shift count. +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "lshd %$%n2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "lshd %2,%0") + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "lshw %$%n2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "lshw %2,%0") + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "lshb %$%n2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "lshb %2,%0") + +;; Rotate instructions + +(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")))] + "" + "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")))] + "" + "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")))] + "" + "rotb %2,%0") + +;; Right rotate on the 32k works by negating the shift count. +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "rotd %$%n2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g") + (rotatert:SI (match_operand:SI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "rotd %2,%0") + +(define_expand "rotrhi3" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotatert:HI (match_operand:HI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "rotw %$%n2,%0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (rotatert:HI (match_operand:HI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "rotw %2,%0") + +(define_expand "rotrqi3" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotatert:QI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "general_operand" "g")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT) + operands[2] = gen_rtx (NEG, SImode, negate_rtx (SImode, operands[2])); +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")))] + "" + "rotb %$%n2,%0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g") + (rotatert:QI (match_operand:QI 1 "general_operand" "0") + (neg:SI (match_operand:SI 2 "general_operand" "r"))))] + "" + "rotb %2,%0") + +;;- load or push effective address +;; These come after the move, add, and multiply patterns +;; because we don't want pushl $1 turned into pushad 1. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + if (REG_P (operands[0]) + && GET_CODE (operands[1]) == MULT + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && (INTVAL (XEXP (operands[1], 1)) == 2 + || INTVAL (XEXP (operands[1], 1)) == 4)) + { + rtx xoperands[3]; + xoperands[0] = operands[0]; + xoperands[1] = XEXP (operands[1], 0); + xoperands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (XEXP (operands[1], 1)) >> 1); + return output_shift_insn (xoperands); + } + return \"addr %a1,%0\"; +}") + +;;; 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 +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=r") +; (plus:SI (match_operand:SI 1 "general_operand" "rmn") +; (mult:SI (match_operand:SI 2 "register_operand" "0") +; (plus:SI (match_operand:SI 3 "general_operand" "rmn") (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")))] +; "GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > 8" +; "indexd %0,%2,%3") + +;; Set, Clear, and Invert bit + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (const_int 1))] + "" + "sbitd %1,%0") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+g") + (const_int 1) + (match_operand:SI 1 "general_operand" "rmn")) + (const_int 0))] + "" + "cbitd %1,%0") + +(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_dup 0)))] + "" + "ibitd %1,%0") + +(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_dup 0)))] + "" + "ibitb %1,%0") + +;; Recognize jbs and jbc instructions. + +(define_insn "" + [(set (cc0) + (zero_extract (match_operand:SI 0 "general_operand" "rm") + (const_int 1) + (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ cc_status.flags = CC_Z_IN_F; + return \"tbitd %1,%0\"; +}") + +;; extract(base, width, offset) +;; Signed bitfield extraction is not supported in hardware on the +;; NS 32032. It is therefore better to let GCC figure out a +;; good strategy for generating the proper instruction sequence +;; and represent it as rtl. + +;; Optimize the case of extracting a byte or word from a register. +;; Otherwise we must load a register with the offset of the +;; chunk we want, and perform an extract insn (each of which +;; is very expensive). Since we use the stack to do our bit-twiddling +;; we cannot use it for a destination. Perhaps things are fast +;; enough on the 32532 that such hacks are not needed. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=ro") + (zero_extract:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "const_int_operand" "i")))] + "(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && (INTVAL (operands[3]) == 8 || INTVAL (operands[3]) == 16 || INTVAL (operands[3]) == 24)" + "* +{ + output_asm_insn (\"movd %1,tos\", operands); + if (INTVAL (operands[2]) == 16) + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzwd 1(sp),%0\", operands); + else + output_asm_insn (\"movzwd 2(sp),%0\", operands); + } + else + { + if (INTVAL (operands[3]) == 8) + output_asm_insn (\"movzbd 1(sp),%0\", operands); + else if (INTVAL (operands[3]) == 16) + output_asm_insn (\"movzbd 2(sp),%0\", operands); + else + output_asm_insn (\"movzbd 3(sp),%0\", operands); + } + if (TARGET_32532 || TARGET_32332) + return \"cmpqd %$0,tos\"; + else + return \"adjspb %$-4\"; +}") + +;; The exts/ext instructions have the problem that they always access +;; 32 bits even if the bitfield is smaller. For example the instruction +;; extsd 7(r1),r0,2,5 +;; would read not only at address 7(r1) but also at 8(r1) to 10(r1). +;; If these addresses are in a different (unmapped) page a memory fault +;; is the result. +;; +;; Timing considerations: +;; movd 0(r1),r0 3 bytes +;; lshd -26,r0 4 +;; andd 0x1f,r0 5 +;; takes about 13 cycles on the 532 while +;; extsd 7(r1),r0,2,5 5 bytes +;; takes about 21 cycles. +;; +;; The inss/ins instructions suffer from the same problem. +;; +;; A machine specific option (-mbitfield/-mnobitfield) is used +;; to allow/disallow the use of these instructions. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extract:SI (match_operand:SI 1 "register_operand" "g") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "general_operand" "rK")))] + "TARGET_BITFIELD" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + return \"extsd %1,%0,%3,%2\"; + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "extzv" + [(set (match_operand:SI 0 "general_operand" "=g<") + (zero_extract:SI (match_operand:QI 1 "general_operand" "g") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "general_operand" "rK")))] + "TARGET_BITFIELD" + "* +{ if (GET_CODE (operands[3]) == CONST_INT) + return \"extsd %1,%0,%3,%2\"; + else return \"extd %3,%1,%0,%2\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "memory_operand" "+o") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "general_operand" "rn")) + (match_operand:SI 3 "general_operand" "rm"))] + "TARGET_BITFIELD" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) >= 8) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[2]) / 8); + operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) % 8); + } + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + } + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "general_operand" "rK")) + (match_operand:SI 3 "general_operand" "rm"))] + "TARGET_BITFIELD" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + return \"insd %2,%3,%0,%1\"; +}") + +(define_insn "insv" + [(set (zero_extract:SI (match_operand:QI 0 "general_operand" "+g") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "general_operand" "rK")) + (match_operand:SI 3 "general_operand" "rm"))] + "TARGET_BITFIELD" + "* +{ if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[1]) <= 8) + return \"inssb %3,%0,%2,%1\"; + else if (INTVAL (operands[1]) <= 16) + return \"inssw %3,%0,%2,%1\"; + else + return \"inssd %3,%0,%2,%1\"; + return \"insd %2,%3,%0,%1\"; +}") + + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br %l0") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bgt %l0") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhi %l0") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blt %l0") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blo %l0") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bge %l0") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bhs %l0") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "ble %l0") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfs %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfc %l0\"; + else return \"bne %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"bfc %l0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"bfs %l0\"; + else return \"beq %l0\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "ble %l0") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bls %l0") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bge %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhs %l0") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "blo %l0") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bgt %l0") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "bhi %l0") + +;; Subtract-and-jump and Add-and-jump insns. +;; These can actually be used for adding numbers in the range -8 to 7 + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "const_int_operand" "i")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_dup 1)))] + "INTVAL (operands[1]) > -8 && INTVAL (operands[1]) <= 8" + "acbd %$%n1,%0,%l2") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "general_operand" "+g") + (match_operand:SI 1 "const_int_operand" "i")) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 3 "const_int_operand" "i")))] + "INTVAL (operands[1]) == - INTVAL (operands[3]) + && INTVAL (operands[3]) >= -8 && INTVAL (operands[3]) < 8" + "acbd %3,%0,%l2") + +(define_insn "call" + [(call (match_operand:QI 0 "memory_operand" "m") + (match_operand:QI 1 "general_operand" "g"))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[0]) == MEM) + { + rtx temp = XEXP (operands[0], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef ENCORE_ASM + return \"bsr %?%0\"; +#else +#ifdef CALL_MEMREF_IMPLICIT + operands[0] = temp; + return \"bsr %0\"; +#else +#ifdef GNX_V3 + return \"bsr %0\"; +#else + return \"bsr %?%a0\"; +#endif +#endif +#endif + } + if (GET_CODE (XEXP (operands[0], 0)) == REG) +#if defined (GNX_V3) || defined (CALL_MEMREF_IMPLICIT) + return \"jsr %0\"; +#else + return \"jsr %a0\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %0\"; +}") + +(define_insn "call_value" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "g")))] + "" + "* +{ +#ifndef JSR_ALWAYS + if (GET_CODE (operands[1]) == MEM) + { + rtx temp = XEXP (operands[1], 0); + if (CONSTANT_ADDRESS_P (temp)) + { +#ifdef ENCORE_ASM + return \"bsr %?%1\"; +#else +#ifdef CALL_MEMREF_IMPLICIT + operands[1] = temp; + return \"bsr %1\"; +#else +#ifdef GNX_V3 + return \"bsr %1\"; +#else + return \"bsr %?%a1\"; +#endif +#endif +#endif + } + if (GET_CODE (XEXP (operands[1], 0)) == REG) +#if defined (GNX_V3) || defined (CALL_MEMREF_IMPLICIT) + return \"jsr %1\"; +#else + return \"jsr %a1\"; +#endif + } +#endif /* not JSR_ALWAYS */ + return \"jsr %1\"; +}") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "") + +(define_insn "return" + [(return)] + "0" + "ret 0") + +(define_insn "abssf2" + [(set (match_operand:SF 0 "general_operand" "=fm<") + (abs:SF (match_operand:SF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absf %1,%0") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "general_operand" "=fm<") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_32081" + "absl %1,%0") + +(define_insn "abssi2" + [(set (match_operand:SI 0 "general_operand" "=g<") + (abs:SI (match_operand:SI 1 "general_operand" "rmn")))] + "" + "absd %1,%0") + +(define_insn "abshi2" + [(set (match_operand:HI 0 "general_operand" "=g<") + (abs:HI (match_operand:HI 1 "general_operand" "g")))] + "" + "absw %1,%0") + +(define_insn "absqi2" + [(set (match_operand:QI 0 "general_operand" "=g<") + (abs:QI (match_operand:QI 1 "general_operand" "g")))] + "" + "absb %1,%0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jump %0") + +(define_insn "tablejump" + [(set (pc) + (plus:SI (pc) (match_operand:SI 0 "general_operand" "g"))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (operands[1])); + return \"cased %0\"; +}") + +;; Scondi instructions +(define_insn "seq" + [(set (match_operand:SI 0 "general_operand" "=g<") + (eq:SI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsd %0\"; + else return \"seqd %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (eq:HI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsw %0\"; + else return \"seqw %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (eq:QI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfcb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfsb %0\"; + else return \"seqb %0\"; +}") + +(define_insn "sne" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ne:SI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsd %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcd %0\"; + else return \"sned %0\"; +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ne:HI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsw %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcw %0\"; + else return \"snew %0\"; +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ne:QI (cc0) (const_int 0)))] + "" + "* +{ if (cc_prev_status.flags & CC_Z_IN_F) + return \"sfsb %0\"; + else if (cc_prev_status.flags & CC_Z_IN_NOT_F) + return \"sfcb %0\"; + else return \"sneb %0\"; +}") + +(define_insn "sgt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gt:SI (cc0) (const_int 0)))] + "" + "sgtd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gt:HI (cc0) (const_int 0)))] + "" + "sgtw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gt:QI (cc0) (const_int 0)))] + "" + "sgtb %0") + +(define_insn "sgtu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (gtu:SI (cc0) (const_int 0)))] + "" + "shid %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (gtu:HI (cc0) (const_int 0)))] + "" + "shiw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (gtu:QI (cc0) (const_int 0)))] + "" + "shib %0") + +(define_insn "slt" + [(set (match_operand:SI 0 "general_operand" "=g<") + (lt:SI (cc0) (const_int 0)))] + "" + "sltd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (lt:HI (cc0) (const_int 0)))] + "" + "sltw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (lt:QI (cc0) (const_int 0)))] + "" + "sltb %0") + +(define_insn "sltu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ltu:SI (cc0) (const_int 0)))] + "" + "slod %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ltu:HI (cc0) (const_int 0)))] + "" + "slow %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ltu:QI (cc0) (const_int 0)))] + "" + "slob %0") + +(define_insn "sge" + [(set (match_operand:SI 0 "general_operand" "=g<") + (ge:SI (cc0) (const_int 0)))] + "" + "sged %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (ge:HI (cc0) (const_int 0)))] + "" + "sgew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (ge:QI (cc0) (const_int 0)))] + "" + "sgeb %0") + +(define_insn "sgeu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (geu:SI (cc0) (const_int 0)))] + "" + "shsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (geu:HI (cc0) (const_int 0)))] + "" + "shsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (geu:QI (cc0) (const_int 0)))] + "" + "shsb %0") + +(define_insn "sle" + [(set (match_operand:SI 0 "general_operand" "=g<") + (le:SI (cc0) (const_int 0)))] + "" + "sled %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (le:HI (cc0) (const_int 0)))] + "" + "slew %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (le:QI (cc0) (const_int 0)))] + "" + "sleb %0") + +(define_insn "sleu" + [(set (match_operand:SI 0 "general_operand" "=g<") + (leu:SI (cc0) (const_int 0)))] + "" + "slsd %0") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g<") + (leu:HI (cc0) (const_int 0)))] + "" + "slsw %0") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=g<") + (leu:QI (cc0) (const_int 0)))] + "" + "slsb %0") + +;; ffs instructions + +(define_insn "ffsqi2" + [(set (match_operand:QI 0 "general_operand" "=g") + (ffs:QI (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + return \"movqb 0,%0; ffsd %1,%0; bfs 1f; addqb 1,%0; 1:\"; +}") + +(define_insn "ffshi2" + [(set (match_operand:HI 0 "general_operand" "=g") + (ffs:HI (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + return \"movqw 0,%0; ffsd %1,%0; bfs 1f; addqw 1,%0; 1:\"; +}") + +(define_insn "ffssi2" + [(set (match_operand:SI 0 "general_operand" "=g") + (ffs:SI (match_operand:SI 1 "general_operand" "g")))] + "" + "* +{ + return \"movqd 0,%0; ffsd %1,%0; bfs 1f; addqd 1,%0; 1:\"; +}") + +;; 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 (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\"), + operands); + else + output_asm_insn (\"movzwd %1,tos\", operands); + return \"\"; +}") + +;; 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 (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\"), + operands); + else + output_asm_insn (\"movzbd %1,tos\", operands); + return \"\"; +}") + +;; 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 (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\"), + operands); + else + output_asm_insn (\"movxbd %1,tos\", operands); + return \"\"; +}") + +;; 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 (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\"), + operands); + else + output_asm_insn (\"movzbd %1,tos\", operands); + return \"\"; +}") + +;; 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 (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)\"), + operands); + else if (GET_CODE (operands[1]) != REG + && GET_CODE (operands[1]) != MEM + && address_operand (operands[1], SImode)) + output_asm_insn (\"addr %a1,0(sp)\", operands); + else + output_asm_insn (\"movd %1,0(sp)\", operands); + return \"\"; +}") + +;; 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 (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "general_operand" "g")) + (set (match_operand:SI 2 "push_operand" "=m") + (match_operand:SI 3 "general_operand" "g"))] + "! reg_mentioned_p (stack_pointer_rtx, operands[1]) + && ! reg_mentioned_p (stack_pointer_rtx, operands[3])" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + 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 + && address_operand (operands[1], SImode)) + output_asm_insn (\"addr %a1,4(sp)\", operands); + else + 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)\"), + operands); + else if (GET_CODE (operands[3]) != REG + && GET_CODE (operands[3]) != MEM + && address_operand (operands[3], SImode)) + output_asm_insn (\"addr %a3,0(sp)\", operands); + else + output_asm_insn (\"movd %3,0(sp)\", operands); + return \"\"; +}") diff --git a/gnu/usr.bin/gcc/config/ns32k/pc532-mach.h b/gnu/usr.bin/gcc/config/ns32k/pc532-mach.h new file mode 100644 index 00000000000..0aeabad32d9 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/pc532-mach.h @@ -0,0 +1,30 @@ +/* Definitions of target machine for GNU compiler. + PC532 with National 32532, running Mach 3.0. + Copyright (C) 1992, 1994 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ns32k/pc532.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dns32532 -DPC532 -DMACH=1 -Asystem(unix) -Asystem(mach) -Acpu(ns32k) -Amachine(ns32k)" + +/* There's a bug in the setjmp implementation that strikes + if the caller of setjmp doesn't have a frame pointer. */ +#undef FRAME_POINTER_REQUIRED +#define FRAME_POINTER_REQUIRED current_function_calls_setjmp diff --git a/gnu/usr.bin/gcc/config/ns32k/pc532-min.h b/gnu/usr.bin/gcc/config/ns32k/pc532-min.h new file mode 100644 index 00000000000..9d3d5de7556 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/pc532-min.h @@ -0,0 +1,41 @@ +/* Definitions of target machine for GNU compiler. + PC532 with National 32532, running Minix. + Works with pc532 Minix 1.5hybrid. + Copyright (C) 1990 Free Software Foundation, Inc. + + Derived from SEQUENT NS32000, written originally + by Bruce Culbertson <culberts@hplabs.hp.com>, + hacked for easier fit in gcc by Jyrki Kuoppala <jkp@cs.hut.fi>. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ns32k/pc532.h" + +/* Minix has crtso.o instead of crt0.o */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrtso.o%s}%{!pg:%{p:mcrtso.o%s}%{!p:crtso.o%s}}" + +/* our setjmp doesn't save registers, so we must tell gcc to save + call-saved-regs in a function calling setjmp */ + +#define NON_SAVING_SETJMP (current_function_calls_setjmp) + +/* at least with estdio there's no _cleanup() but we have atexit() */ + +#define HAVE_ATEXIT diff --git a/gnu/usr.bin/gcc/config/ns32k/pc532.h b/gnu/usr.bin/gcc/config/ns32k/pc532.h new file mode 100644 index 00000000000..d98bf43d044 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/pc532.h @@ -0,0 +1,73 @@ +/* Definitions of target machine for GNU compiler. + PC532 with National 32532. + Copyright (C) 1990, 1994 Free Software Foundation, Inc. + Contributed by Jukka Virtanen <jtv@hut.fi>, Jyrki Kuoppala <jkp@cs.hut.fi>, + Tatu Yl|nen <ylo@ngs.fi>, Johannes Helander <jvh@cs.hut.fi>. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ns32k/ns32k.h" + +/* Compile for the floating point unit & 32532 by default; + also presume SB is zero and no bitfield instructions */ + +#define TARGET_DEFAULT (1 + 24 + 64) + +/* Write DBX debugging info for gdb to read */ + +#define DBX_DEBUGGING_INFO + +/* Use the re-entrant and potentially faster method */ + +#undef PCC_STATIC_STRUCT_RETURN + +/* 32-bit alignment for efficiency */ +#undef POINTER_BOUNDARY +#define POINTER_BOUNDARY 32 + +/* 32-bit alignment for efficiency */ +#undef FUNCTION_BOUNDARY +#define FUNCTION_BOUNDARY 32 + +/* 32532 spec says it can handle any alignment. Rumor from tm-ns32k.h + tells this might not be actually true (but it's for 32032, perhaps + National has fixed the bug for 32532). You might have to change this + if the bug still exists. */ + +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 + +/* Maybe someone needs to know which processor we're running on */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dns32000 -Dns32532 -Dpc532 -Dunix -Asystem(unix) -Acpu(ns32k) -Amachine(ns32k)" + +/* Use pc relative addressing whenever possible, + it's more efficient than absolute (ns32k.c) + You have to fix a bug in gas 1.38.1 to make this work with gas, + patch available from jkp@cs.hut.fi. */ + +#define PC_RELATIVE + +/* Operand of bsr or jsr should be just the address. */ + +#define CALL_MEMREF_IMPLICIT + +/* movd insns may have floating point constant operands. */ + +#define MOVD_FLOAT_OK diff --git a/gnu/usr.bin/gcc/config/ns32k/sequent.h b/gnu/usr.bin/gcc/config/ns32k/sequent.h new file mode 100644 index 00000000000..1165aa31d36 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/sequent.h @@ -0,0 +1,77 @@ +/* Definitions of target machine for GNU compiler. SEQUENT NS32000 version. + Copyright (C) 1987 Free Software Foundation, Inc. + Contributed by Michael Tiemann (tiemann@mcc.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "ns32k/ns32k.h" + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +#define TARGET_DEFAULT 9 /* 32332 with 32081 (guessing). */ + +/* Print subsidiary information on the compiler version in use. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (32000, Sequent syntax)"); + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dns32000 -Dsequent -Dunix -Asystem(unix) -Asystem(bsd) -Acpu(ns32k) -Amachine(ns32k)" + +/* Link with libg.a when debugging, for dbx's sake. */ + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* gcc should find libgcc.a itself, not ask linker to do so. */ + +#define LINK_LIBGCC_SPECIAL + +/* GCC must match what sys/types.h uses for size_t. */ + +#define SIZE_TYPE "int" + +/* This is how to align the code that follows an unconditional branch. + Don't define it, since it confuses the assembler (we hear). */ + +#undef ASM_OUTPUT_ALIGN_CODE + +/* Assembler pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +/* Control how stack adjust insns are output. */ +#define SEQUENT_ADJUST_STACK + +#define NO_ABSOLUTE_PREFIX_IF_SYMBOLIC + +#define IMMEDIATE_PREFIX 0 + +#define SEQUENT_ASM + +/* Operand of bsr or jsr should be just the address. */ + +#define CALL_MEMREF_IMPLICIT + +/* Output a reg as an index rather than a base if we have the choice. */ + +#define INDEX_RATHER_THAN_BASE diff --git a/gnu/usr.bin/gcc/config/ns32k/tek6000.h b/gnu/usr.bin/gcc/config/ns32k/tek6000.h new file mode 100644 index 00000000000..00ddc96498b --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/tek6000.h @@ -0,0 +1,235 @@ +/* Definitions of target machine for GNU compiler. + Generic Tektronix 6000 series NS32000 version. + See ns32k/tek6100.h and ns32k/tek6200.h, which include this file. + Copyright (C) 1990 Free Software Foundation, Inc. + Created by Snoopy (sopwith.uucp!snoopy). + Based on work by Mark Mason (mason@reed.bitnet, + pyramid!unify!mason@uunet.uu.net) and Keith Packard. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Generate syntax for the UTek assembler. */ +#ifndef UTEK_ASM +#define UTEK_ASM +#endif + +/* Two flags to control how addresses are printed in assembler insns. */ + +/* The way PUT_ABSOLUTE_PREFIX in ns32k.h works, setting it to 0 will + * turn it off. Define ABSOLUTE_PREFIX before including ns32k.h. + */ +#define ABSOLUTE_PREFIX 0 +#define IMMEDIATE_PREFIX '$' + +#include "ns32k/ns32k.h" + +/* Define these after ns32k.c so we will notice if gcc tries to + * output external mode addressing. UTek's as and ld do not support + * external mode addressing, according to Daryl McDaniel (illian.uucp!darylm). + * Hopefully the UTek assembler will complain if gcc feeds it this stuff. + * They don't seem to do anything, I think that gcc is not actually + * trying to generate external mode operands. + */ +#undef PUT_EXTERNAL_PREFIX +#define PUT_EXTERNAL_PREFIX(arg) fprintf(arg, " Should not be using external mode under UTek. ") +#define EXTERNAL_PREFIX '%' + +/* Used in ns32k.c to control syntax. */ +#define NO_ABSOLUTE_PREFIX_IF_SYMBOLIC +#define NO_IMMEDIATE_PREFIX_IF_SYMBOLIC + +/* Used in ns32k.md to specify syntax of bsr/jsr operand. */ +#define CALL_MEMREF_IMPLICIT + +/* #define PC_RELATIVE */ /* Seems to break things. */ +#define BASE_REG_NEEDED /* Seems to fix problem where external mode + * syntax was being generated. + */ + +/* ------------ Debugging Support ----------------------------- */ + +/* The sdb support does not yet work with UTek. Need to teach gcc + * how to create sdb type stabs as well as dbx style stabs. + */ +#define DBX_DEBUGGING_INFO +/* #define SDB_DEBUGGING_INFO */ + +/* Act the same as the UTek complier: -g for dbx, -go for sdb. + * This is used in toplev.c. + */ +#define PREFERRED_DEBUGGING_TYPE \ + ((len > 1 && !strncmp(str, "go", len)) ? SDB_DEBUG : DBX_DEBUG ) + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 + +/* ------------------------------------------- */ + +#define TARGET_DEFAULT 1 + +/* These control the C++ compiler somehow. */ +#define FASCIST_ASSEMBLER +#define USE_COLLECT + +/* Print subsidiary information on the compiler version in use. */ +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (ns32k, UTek syntax)"); + +/* The tek6100.h and tek6200.h files add stratos or merlin respectively. */ + +#define CPP_PREDEFINES_Tek6000 \ + "-Dns16000 -Dns32000 -Dns32k -Dns32016 -DUTek -DUTEK -Dbsd -DBSD \ + -Asystem(unix) -Asystem(bsd) -Acpu(ns32k) -Amachine(ns32k)" +#undef CPP_PREDEFINES +#define CPP_PREDEFINES CPP_PREDEFINES_Tek6000 + +/* This is how to align the code that follows an unconditional branch. + Don't define it, since it confuses the assembler (we hear). */ + +#undef ASM_OUTPUT_ALIGN_CODE + +/* Assembler pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +#ifdef UTEK_ASM +#undef FUNCTION_PROLOGUE + +/* This differs from the one in ns32k.h in printing a bitmask + rather than a register list in the enter or save instruction. */ + +#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; \ + extern char call_used_regs[]; \ + MAIN_FUNCTION_PROLOGUE; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + *bufp = -1; \ + for (; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; \ + } \ + *fbufp = -1; \ + bufp = used_regs_buf; \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tenter "); \ + else if (g_regs_used) \ + fprintf (FILE, "\tsave "); \ + if (frame_pointer_needed || g_regs_used) \ + { \ + char mask = 0; \ + while (*bufp >= 0) \ + mask |= 1 << *bufp++; \ + fprintf (FILE, "$0x%x", (int) mask & 0xff); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, ",$%d\n", SIZE); \ + else if (g_regs_used) \ + fprintf (FILE, "\n"); \ + fbufp = used_fregs_buf; \ + while (*fbufp >= 0) \ + { \ + if ((*fbufp & 1) || (fbufp[0] != fbufp[1] - 1)) \ + fprintf (FILE, "\tmovf f%d,tos\n", *fbufp++ - 8); \ + else \ + { \ + fprintf (FILE, "\tmovl f%d,tos\n", fbufp[0] - 8); \ + fbufp += 2; \ + } \ + } \ +} + +#undef FUNCTION_EPILOGUE + +/* This differs from the one in ns32k.h in printing a bitmask + rather than a register list in the exit or restore instruction. */ + +#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; \ + extern char call_used_regs[]; \ + *fbufp++ = -2; \ + for (regno = 8; regno < 16; regno++) \ + if (regs_ever_live[regno] && !call_used_regs[regno]) { \ + *fbufp++ = regno; f_regs_used++; \ + } \ + fbufp--; \ + for (regno = 0; regno < 8; regno++) \ + if (regs_ever_live[regno] \ + && ! call_used_regs[regno]) \ + { \ + *bufp++ = regno; g_regs_used++; \ + } \ + while (fbufp > used_fregs_buf) \ + { \ + if ((*fbufp & 1) && fbufp[0] == fbufp[-1] + 1) \ + { \ + fprintf (FILE, "\tmovl tos,f%d\n", fbufp[-1] - 8); \ + fbufp -= 2; \ + } \ + else fprintf (FILE, "\tmovf tos,f%d\n", *fbufp-- - 8); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\texit "); \ + else if (g_regs_used) \ + fprintf (FILE, "\trestore "); \ + if (g_regs_used || frame_pointer_needed) \ + { \ + char mask = 0; \ + \ + while (bufp > used_regs_buf) \ + { \ + /* Utek assembler takes care of reversing this */ \ + mask |= 1 << *--bufp; \ + } \ + fprintf (FILE, "$0x%x\n", (int) mask & 0xff); \ + } \ + if (current_function_pops_args) \ + fprintf (FILE, "\tret $%d\n", current_function_pops_args); \ + else fprintf (FILE, "\tret $0\n"); } + +/* UTek assembler needs "ret $0", not "ret 0". */ +#undef TRANSFER_FROM_TRAMPOLINE +#define TRANSFER_FROM_TRAMPOLINE \ +void \ +__transfer_from_trampoline () \ +{ \ + asm ("___trampoline:"); \ + asm ("movd 16(r2),tos"); \ + asm ("movd 12(r2),r2"); \ + asm ("ret $0"); \ +} + +#endif /* UTEK_ASM */ + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address(FILE, ADDR) + +/* The UTek library supplies bcopy() and friends, not memcpy(). */ +#ifdef TARGET_MEM_FUNCTIONS +#undef TARGET_MEM_FUNCTIONS +#endif diff --git a/gnu/usr.bin/gcc/config/ns32k/tek6100.h b/gnu/usr.bin/gcc/config/ns32k/tek6100.h new file mode 100644 index 00000000000..e5b385f1272 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/tek6100.h @@ -0,0 +1,7 @@ +#include "ns32k/tek6000.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Dns32000 -Dns32k -Dns16000 -Dns32016 -DUTek -DUTEK -Dbsd -DBSD -Dstratos \ + -Asystem(unix) -Asystem(bsd) -Acpu(ns32k) -Amachine(ns32k)" + diff --git a/gnu/usr.bin/gcc/config/ns32k/tek6200.h b/gnu/usr.bin/gcc/config/ns32k/tek6200.h new file mode 100644 index 00000000000..c03f25534e7 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/tek6200.h @@ -0,0 +1,7 @@ +#include "ns32k/tek6000.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Dns32000 -Dns32k -Dns16000 -Dns32016 -DUTek -DUTEK -Dbsd -DBSD -Dmerlin \ + -Asystem(unix) -Asystem(bsd) -Acpu(ns32k) -Amachine(ns32k)" + diff --git a/gnu/usr.bin/gcc/config/ns32k/x-genix b/gnu/usr.bin/gcc/config/ns32k/x-genix new file mode 100644 index 00000000000..0598df8a193 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/x-genix @@ -0,0 +1,6 @@ +# Makefile modifications for compilation on Genix. +ALLOCA=alloca.o +MALLOC = malloc.o + +# You must get malloc.c and getpagesize.h from GNU Emacs. + diff --git a/gnu/usr.bin/gcc/config/ns32k/xm-genix.h b/gnu/usr.bin/gcc/config/ns32k/xm-genix.h new file mode 100644 index 00000000000..76be3b76fc8 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/xm-genix.h @@ -0,0 +1,9 @@ +/* Config file for ns32k running system V. */ + +#include "ns32k/xm-ns32k.h" + +#define USG + +#define bcopy(a,b,c) memcpy (b,a,c) +#define bzero(a,b) memset (a,0,b) +#define bcmp(a,b,c) memcmp (a,b,c) diff --git a/gnu/usr.bin/gcc/config/ns32k/xm-netbsd.h b/gnu/usr.bin/gcc/config/ns32k/xm-netbsd.h new file mode 100644 index 00000000000..4040751d1d9 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/xm-netbsd.h @@ -0,0 +1,10 @@ +/* Configuration for GCC for ns32k running NetBSD as host. */ + +#include <ns32k/xm-ns32k.h> + +/* ns32k/xm-ns32k.h defines these macros, but we don't need them */ +#undef memcmp +#undef memcpy +#undef memset + +#include <xm-netbsd.h> diff --git a/gnu/usr.bin/gcc/config/ns32k/xm-ns32k.h b/gnu/usr.bin/gcc/config/ns32k/xm-ns32k.h new file mode 100644 index 00000000000..a5ef3375da8 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/xm-ns32k.h @@ -0,0 +1,42 @@ +/* Configuration for GNU C-compiler for Vax. + Copyright (C) 1987, 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* This describes the machine the compiler is hosted on. */ +#define HOST_BITS_PER_CHAR 8 +#define HOST_BITS_PER_SHORT 16 +#define HOST_BITS_PER_INT 32 +#define HOST_BITS_PER_LONG 32 +#define HOST_BITS_PER_LONGLONG 64 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +#define memcpy(src,dst,len) bcopy ((dst),(src),(len)) +#define memset gcc_memset +#define memcmp(left,right,len) bcmp ((left),(right),(len)) diff --git a/gnu/usr.bin/gcc/config/ns32k/xm-pc532-min.h b/gnu/usr.bin/gcc/config/ns32k/xm-pc532-min.h new file mode 100644 index 00000000000..a200792a0b2 --- /dev/null +++ b/gnu/usr.bin/gcc/config/ns32k/xm-pc532-min.h @@ -0,0 +1,34 @@ +/* Configuration for GNU C-compiler for PC532 running Minix + Copyright (C) 1987,1990 Free Software Foundation, Inc. + Contributed by Jyrki Kuoppala <jkp@cs.hut.fi>, August 1990 + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* We have USG-style include files and time functions */ + +#define USG + +#include "ns32k/xm-ns32k.h" + +#ifndef HZ +#define HZ 60 +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif |