summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/gcc/config/tahoe
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1995-12-20 01:06:22 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1995-12-20 01:06:22 +0000
commitc482518380683ee38d14024c1e362a0d681cf967 (patch)
treee69b4f6d3fee3aced20a41f3fdf543fc1c77fb5d /gnu/usr.bin/gcc/config/tahoe
parent76a62188d0db49c65b696d474c855a799fd96dce (diff)
FSF GCC version 2.7.2
Diffstat (limited to 'gnu/usr.bin/gcc/config/tahoe')
-rw-r--r--gnu/usr.bin/gcc/config/tahoe/harris.h87
-rw-r--r--gnu/usr.bin/gcc/config/tahoe/tahoe.c565
-rw-r--r--gnu/usr.bin/gcc/config/tahoe/tahoe.h1016
-rw-r--r--gnu/usr.bin/gcc/config/tahoe/tahoe.md2113
-rw-r--r--gnu/usr.bin/gcc/config/tahoe/xm-tahoe.h59
5 files changed, 3840 insertions, 0 deletions
diff --git a/gnu/usr.bin/gcc/config/tahoe/harris.h b/gnu/usr.bin/gcc/config/tahoe/harris.h
new file mode 100644
index 00000000000..9226445ed98
--- /dev/null
+++ b/gnu/usr.bin/gcc/config/tahoe/harris.h
@@ -0,0 +1,87 @@
+/* Definitions of target machine for GNU compiler. Harris tahoe version.
+ Copyright (C) 1989, 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. */
+
+
+#include "tahoe/tahoe.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dtahoe -Dunix -Dhcx -Asystem(unix) -Acpu(tahoe) -Amachine(tahoe)"
+
+#undef DBX_DEBUGGING_INFO
+#define SDB_DEBUGGING_INFO
+
+#undef LIB_SPEC
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT 1
+
+/* urem and udiv don't exist on this system. */
+#undef UDIVSI3_LIBCALL
+#undef UMODSI3_LIBCALL
+
+/* Operand of .align is not logarithmic. */
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ LOG ? fprintf (FILE, "\t.align %d\n", 1 << (LOG)) : 0
+
+/* For the same reason, we need .align 2 after casesi. */
+#undef PRINT_OPERAND
+#define PRINT_OPERAND(FILE, X, CODE) \
+{ if (CODE == '@') \
+ putc ('2', FILE); \
+ else if (GET_CODE (X) == REG) \
+ fprintf (FILE, "%s", reg_names[REGNO (X)]); \
+ else if (GET_CODE (X) == MEM) \
+ output_address (XEXP (X, 0)); \
+ else { putc ('$', FILE); output_addr_const (FILE, X); }}
+
+#undef ASM_OUTPUT_LOCAL
+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
+( fputs (".bss ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u,4\n", (ROUNDED)))
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ output_file_directive ((FILE), main_input_filename);
+
+#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \
+do { \
+ unsigned char *_p = (PTR); \
+ int _thissize = (SIZE); \
+ fprintf ((FILE), "\t.ascii \""); \
+ for (i = 0; i < _thissize; i++) \
+ { \
+ register int c = _p[i]; \
+ if (c >= ' ' && c < 0177 && c != '\"' && c != '\\') \
+ putc (c, (FILE)); \
+ else \
+ { \
+ fprintf ((FILE), "\\%o", c); \
+ if (i < _thissize - 1 \
+ && _p[i + 1] >= '0' && _p[i + 1] <= '9') \
+ fprintf ((FILE), "\"\n\t.ascii \""); \
+ } \
+ } \
+ fprintf ((FILE), "\"\n"); \
+} while (0)
diff --git a/gnu/usr.bin/gcc/config/tahoe/tahoe.c b/gnu/usr.bin/gcc/config/tahoe/tahoe.c
new file mode 100644
index 00000000000..6fec44418f4
--- /dev/null
+++ b/gnu/usr.bin/gcc/config/tahoe/tahoe.c
@@ -0,0 +1,565 @@
+/* Subroutines for insn-output.c for Tahoe.
+ Copyright (C) 1989, 1991 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 "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"
+
+/*
+ * File: output-tahoe.c
+ *
+ * Original port made at the University of Buffalo by Devon Bowen,
+ * Dale Wiles and Kevin Zachmann.
+ *
+ * Changes for HCX by Piet van Oostrum,
+ * University of Utrecht, The Netherlands (piet@cs.ruu.nl)
+ *
+ * Speed tweaks by Michael Tiemann (tiemann@lurch.stanford.edu).
+ *
+ * Mail bugs reports or fixes to: gcc@cs.buffalo.edu
+ */
+
+
+/* On tahoe, you have to go to memory to convert a register
+ from sub-word to word. */
+
+rtx tahoe_reg_conversion_loc;
+
+int
+extendable_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if ((GET_CODE (op) == REG
+ || (GET_CODE (op) == SUBREG
+ && GET_CODE (SUBREG_REG (op)) == REG))
+ && tahoe_reg_conversion_loc == 0)
+ tahoe_reg_conversion_loc = assign_stack_local (SImode, GET_MODE_SIZE (SImode));
+ return general_operand (op, mode);
+}
+
+/* most of the print_operand_address function was taken from the vax */
+/* since the modes are basically the same. I had to add a special case, */
+/* though, for symbol references with offsets. */
+
+#include <stdio.h>
+
+print_operand_address (file, addr)
+ FILE *file;
+ register rtx addr;
+{
+ register rtx reg1, reg2, breg, ireg;
+ rtx offset;
+ static char *reg_name[] = REGISTER_NAMES;
+
+ retry:
+ switch (GET_CODE (addr))
+ {
+ case MEM:
+ fprintf (file, "*");
+ addr = XEXP (addr, 0);
+ goto retry;
+
+ case REG:
+ fprintf (file, "(%s)", reg_name [REGNO (addr)]);
+ break;
+
+ case PRE_DEC:
+ fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
+ break;
+
+ case POST_INC:
+ fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
+ break;
+
+ case PLUS:
+ reg1 = 0; reg2 = 0;
+ ireg = 0; breg = 0;
+ offset = 0;
+
+ if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+ output_addr_const (file, addr);
+
+ if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
+ && GET_CODE (XEXP (addr, 0)) == CONST_INT)
+ output_addr_const (file, addr);
+
+ if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
+ || GET_CODE (XEXP (addr, 0)) == MEM)
+ {
+ offset = XEXP (addr, 0);
+ addr = XEXP (addr, 1);
+ }
+ else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
+ || GET_CODE (XEXP (addr, 1)) == MEM)
+ {
+ offset = XEXP (addr, 1);
+ addr = XEXP (addr, 0);
+ }
+ if (GET_CODE (addr) != PLUS)
+ ;
+ else if (GET_CODE (XEXP (addr, 0)) == MULT)
+ {
+ reg1 = XEXP (addr, 0);
+ addr = XEXP (addr, 1);
+ }
+ else if (GET_CODE (XEXP (addr, 1)) == MULT)
+ {
+ reg1 = XEXP (addr, 1);
+ addr = XEXP (addr, 0);
+ }
+ else if (GET_CODE (XEXP (addr, 0)) == REG)
+ {
+ reg1 = XEXP (addr, 0);
+ addr = XEXP (addr, 1);
+ }
+ else if (GET_CODE (XEXP (addr, 1)) == REG)
+ {
+ reg1 = XEXP (addr, 1);
+ addr = XEXP (addr, 0);
+ }
+ if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
+ {
+ if (reg1 == 0)
+ reg1 = addr;
+ else
+ reg2 = addr;
+ addr = 0;
+ }
+ if (offset != 0)
+ {
+ if (addr != 0) abort ();
+ addr = offset;
+ }
+ if (reg1 != 0 && GET_CODE (reg1) == MULT)
+ {
+ breg = reg2;
+ ireg = reg1;
+ }
+ else if (reg2 != 0 && GET_CODE (reg2) == MULT)
+ {
+ breg = reg1;
+ ireg = reg2;
+ }
+ else if (reg2 != 0 || GET_CODE (addr) == MEM)
+ {
+ breg = reg2;
+ ireg = reg1;
+ }
+ else
+ {
+ breg = reg1;
+ ireg = reg2;
+ }
+ if (addr != 0)
+ output_address (offset);
+ if (breg != 0)
+ {
+ if (GET_CODE (breg) != REG)
+ abort ();
+ fprintf (file, "(%s)", reg_name[REGNO (breg)]);
+ }
+ if (ireg != 0)
+ {
+ if (GET_CODE (ireg) == MULT)
+ ireg = XEXP (ireg, 0);
+ if (GET_CODE (ireg) != REG)
+ abort ();
+ fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
+ }
+ break;
+
+ default:
+ output_addr_const (file, addr);
+ }
+}
+
+/* Do a quick check and find out what the best way to do the */
+/* mini-move is. Could be a push or a move..... */
+
+static char *
+singlemove_string (operands)
+ rtx *operands;
+{
+ if (operands[1] == const0_rtx)
+ return "clrl %0";
+ if (push_operand (operands[0], SImode))
+ return "pushl %1";
+ return "movl %1,%0";
+}
+
+/* given the rtx for an address, return true if the given */
+/* register number is used in the address somewhere. */
+
+regisused(addr,regnum)
+rtx addr;
+int regnum;
+{
+ if (GET_CODE(addr) == REG)
+ if (REGNO(addr) == regnum)
+ return (1);
+ else
+ return (0);
+
+ if (GET_CODE(addr) == MEM)
+ return regisused(XEXP(addr,0),regnum);
+
+ if ((GET_CODE(addr) == MULT) || (GET_CODE(addr) == PLUS))
+ return ((regisused(XEXP(addr,0),regnum)) ||
+ (regisused(XEXP(addr,1),regnum)));
+
+ return 0;
+}
+
+
+/* Given some rtx, traverse it and return the register used in a */
+/* index. If no index is found, return 0. */
+
+rtx
+index_reg(addr)
+rtx addr;
+{
+ rtx temp;
+
+ if (GET_CODE(addr) == MEM)
+ return index_reg(XEXP(addr,0));
+
+ if (GET_CODE(addr) == MULT)
+ if (GET_CODE(XEXP(addr,0)) == REG)
+ return XEXP(addr,0);
+ else
+ return XEXP(addr,1);
+
+ if (GET_CODE(addr) == PLUS)
+ if (temp = index_reg(XEXP(addr,0)))
+ return temp;
+ else
+ return index_reg(XEXP(addr,1));
+
+ return 0;
+}
+
+
+/* simulate the move double by generating two movl's. You have */
+/* to be careful about mixing modes here. */
+
+char *
+output_move_double (operands)
+ rtx *operands;
+{
+ enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP }
+ optype0, optype1;
+ rtx latehalf[2];
+ rtx shftreg0 = 0, shftreg1 = 0;
+ rtx temp0 = 0, temp1 = 0;
+ rtx addreg0 = 0, addreg1 = 0;
+ int dohighfirst = 0;
+
+ /* First classify both operands. */
+
+ if (REG_P (operands[0]))
+ optype0 = REGOP;
+ else if ((GET_CODE(operands[0])==MEM) && (shftreg0=index_reg(operands[0])))
+ optype0 = INDOP;
+ else if (offsettable_memref_p (operands[0]))
+ optype0 = OFFSOP;
+ else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) {
+ optype0 = PUSHOP;
+ dohighfirst++;
+ } else if (GET_CODE (operands[0]) == MEM)
+ optype0 = MEMOP;
+ else
+ optype0 = RNDOP;
+
+ if (REG_P (operands[1]))
+ optype1 = REGOP;
+ else if ((GET_CODE(operands[1])==MEM) && (shftreg1=index_reg(operands[1])))
+ optype1 = INDOP;
+ else if (offsettable_memref_p (operands[1]))
+ optype1 = OFFSOP;
+ else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
+ optype1 = POPOP;
+ else if (GET_CODE (operands[1]) == MEM)
+ optype1 = MEMOP;
+ else if (CONSTANT_P (operands[1]))
+ optype1 = CNSTOP;
+ else
+ optype1 = RNDOP;
+
+ /* set up for the high byte move for operand zero */
+
+ switch (optype0) {
+
+ /* if it's a register, just use the next highest in the */
+ /* high address move. */
+
+ case REGOP : latehalf[0] = gen_rtx (REG,SImode,REGNO(operands[0])+1);
+ break;
+
+ /* for an offsettable address, use the gcc function to */
+ /* modify the operand to get an offset of 4 higher for */
+ /* the second move. */
+
+ case OFFSOP : latehalf[0] = adj_offsettable_operand (operands[0], 4);
+ break;
+
+ /* if the operand is MEMOP type, it must be a pointer */
+ /* to a pointer. So just remember to increase the mem */
+ /* location and use the same operand. */
+
+ case MEMOP : latehalf[0] = operands[0];
+ addreg0 = XEXP(operands[0],0);
+ break;
+
+ /* if we're dealing with a push instruction, just leave */
+ /* the operand alone since it auto-increments. */
+
+ case PUSHOP : latehalf[0] = operands[0];
+ break;
+
+ /* YUCK! Indexed addressing!! If the address is considered */
+ /* offsettable, go use the offset in the high part. Otherwise */
+ /* find what exactly is being added to the multiplication. If */
+ /* it's a mem reference, increment that with the high part */
+ /* being unchanged to cause the shift. If it's a reg, do the */
+ /* same. If you can't identify it, abort. Remember that the */
+ /* shift register was already set during identification. */
+
+ case INDOP : if (offsettable_memref_p(operands[0])) {
+ latehalf[0] = adj_offsettable_operand(operands[0],4);
+ break;
+ }
+
+ latehalf[0] = operands[0];
+
+ temp0 = XEXP(XEXP(operands[0],0),0);
+ if (GET_CODE(temp0) == MULT) {
+ temp1 = temp0;
+ temp0 = XEXP(XEXP(operands[0],0),1);
+ } else {
+ temp1 = XEXP(XEXP(operands[0],0),1);
+ if (GET_CODE(temp1) != MULT)
+ abort();
+ }
+
+ if (GET_CODE(temp0) == MEM)
+ addreg0 = temp0;
+ else if (GET_CODE(temp0) == REG)
+ addreg0 = temp0;
+ else
+ abort();
+
+ break;
+
+ /* if we don't know the operand type, print a friendly */
+ /* little error message... 8-) */
+
+ case RNDOP :
+ default : abort();
+ }
+
+ /* do the same setup for operand one */
+
+ switch (optype1) {
+
+ case REGOP : latehalf[1] = gen_rtx(REG,SImode,REGNO(operands[1])+1);
+ break;
+
+ case OFFSOP : latehalf[1] = adj_offsettable_operand (operands[1], 4);
+ break;
+
+ case MEMOP : latehalf[1] = operands[1];
+ addreg1 = XEXP(operands[1],0);
+ break;
+
+ case POPOP : latehalf[1] = operands[1];
+ break;
+
+ case INDOP : if (offsettable_memref_p(operands[1])) {
+ latehalf[1] = adj_offsettable_operand(operands[1],4);
+ break;
+ }
+
+ latehalf[1] = operands[1];
+
+ temp0 = XEXP(XEXP(operands[1],0),0);
+ if (GET_CODE(temp0) == MULT) {
+ temp1 = temp0;
+ temp0 = XEXP(XEXP(operands[1],0),1);
+ } else {
+ temp1 = XEXP(XEXP(operands[1],0),1);
+ if (GET_CODE(temp1) != MULT)
+ abort();
+ }
+
+ if (GET_CODE(temp0) == MEM)
+ addreg1 = temp0;
+ else if (GET_CODE(temp0) == REG)
+ addreg1 = temp0;
+ else
+ abort();
+
+ break;
+
+ case CNSTOP :
+ if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ split_double (operands[1], &operands[1], &latehalf[1]);
+ else if (CONSTANT_P (operands[1]))
+ latehalf[1] = const0_rtx;
+ else abort ();
+ break;
+
+ case RNDOP :
+ default : abort();
+ }
+
+
+ /* double the register used for shifting in both of the operands */
+ /* but make sure the same register isn't doubled twice! */
+
+ if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
+ output_asm_insn("addl2 %0,%0", &shftreg0);
+ else {
+ if (shftreg0)
+ output_asm_insn("addl2 %0,%0", &shftreg0);
+ if (shftreg1)
+ output_asm_insn("addl2 %0,%0", &shftreg1);
+ }
+
+ /* if the destination is a register and that register is needed in */
+ /* the source addressing mode, swap the order of the moves since we */
+ /* don't want this destroyed til last. If both regs are used, not */
+ /* much we can do, so abort. If these becomes a problem, maybe we */
+ /* can do it on the stack? */
+
+ if (GET_CODE(operands[0])==REG && regisused(operands[1],REGNO(operands[0])))
+ if (regisused(latehalf[1],REGNO(latehalf[0])))
+ 8;
+ else
+ dohighfirst++;
+
+ /* if we're pushing, do the high address part first. */
+
+ if (dohighfirst) {
+
+ if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
+ output_asm_insn("addl2 $4,%0", &addreg0);
+ else {
+ if (addreg0)
+ output_asm_insn("addl2 $4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn("addl2 $4,%0", &addreg1);
+ }
+
+ output_asm_insn(singlemove_string(latehalf), latehalf);
+
+ if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
+ output_asm_insn("subl2 $4,%0", &addreg0);
+ else {
+ if (addreg0)
+ output_asm_insn("subl2 $4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn("subl2 $4,%0", &addreg1);
+ }
+
+ return singlemove_string(operands);
+ }
+
+ output_asm_insn(singlemove_string(operands), operands);
+
+ if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
+ output_asm_insn("addl2 $4,%0", &addreg0);
+ else {
+ if (addreg0)
+ output_asm_insn("addl2 $4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn("addl2 $4,%0", &addreg1);
+ }
+
+ output_asm_insn(singlemove_string(latehalf), latehalf);
+
+ if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
+ output_asm_insn("subl2 $4,%0", &addreg0);
+ else {
+ if (addreg0)
+ output_asm_insn("subl2 $4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn("subl2 $4,%0", &addreg1);
+ }
+
+ if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
+ output_asm_insn("shar $1,%0,%0", &shftreg0);
+ else {
+ if (shftreg0)
+ output_asm_insn("shar $1,%0,%0", &shftreg0);
+ if (shftreg1)
+ output_asm_insn("shar $1,%0,%0", &shftreg1);
+ }
+
+ return "";
+}
+
+
+/* This checks if a zero_extended cmp[bw] can be replaced by a sign_extended
+ cmp[bw]. This can be done if the operand is a constant that fits in a
+ byte/word or a memory operand. Besides that the next instruction must be an
+ unsigned compare. Some of these tests are done by the machine description */
+
+int
+tahoe_cmp_check (insn, op, max)
+rtx insn, op; int max;
+{
+ if (GET_CODE (op) == CONST_INT
+ && ( INTVAL (op) < 0 || INTVAL (op) > max ))
+ return 0;
+ {
+ register rtx next = NEXT_INSN (insn);
+
+ if ((GET_CODE (next) == JUMP_INSN
+ || GET_CODE (next) == INSN
+ || GET_CODE (next) == CALL_INSN))
+ {
+ next = PATTERN (next);
+ if (GET_CODE (next) == SET
+ && SET_DEST (next) == pc_rtx
+ && GET_CODE (SET_SRC (next)) == IF_THEN_ELSE)
+ switch (GET_CODE (XEXP (SET_SRC (next), 0)))
+ {
+ case EQ:
+ case NE:
+ case LTU:
+ case GTU:
+ case LEU:
+ case GEU:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/gnu/usr.bin/gcc/config/tahoe/tahoe.h b/gnu/usr.bin/gcc/config/tahoe/tahoe.h
new file mode 100644
index 00000000000..7eced776b3b
--- /dev/null
+++ b/gnu/usr.bin/gcc/config/tahoe/tahoe.h
@@ -0,0 +1,1016 @@
+/* Definitions of target machine for GNU compiler. Tahoe version.
+ Copyright (C) 1989, 1993, 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. */
+
+/*
+ * Original port made at the University of Buffalo by Devon Bowen,
+ * Dale Wiles and Kevin Zachmann.
+ *
+ * HCX/UX version by Piet van Oostrum (piet@cs.ruu.nl)
+ *
+ * Performance hacking by Michael Tiemann (tiemann@cygnus.com)
+ */
+
+/* define this for the HCX/UX version */
+
+/* #define HCX_UX */
+
+/*
+ * Run-time Target Specification
+ */
+
+#ifdef HCX_UX
+/* no predefines, see Makefile and hcx-universe.c */
+/* have cc1 print that this is the hcx version */
+#define TARGET_VERSION printf (" (hcx)");
+#else
+/* we want "tahoe" and "unix" defined for all future compilations */
+#define CPP_PREDEFINES "-Dtahoe -Dunix -Asystem(unix) -Acpu(tahoe) -Amachine(tahoe)"
+/* have cc1 print that this is the tahoe version */
+#define TARGET_VERSION printf (" (tahoe)");
+#endif
+
+/* this is required in all tm files to hold flags */
+
+extern int target_flags;
+
+/* Zero if it is safe to output .dfloat and .float pseudos. */
+#define TARGET_HEX_FLOAT (target_flags & 1)
+
+#define TARGET_DEFAULT 1
+
+#define TARGET_SWITCHES \
+ { {"hex-float", 1}, \
+ {"no-hex-float", -1}, \
+ { "", TARGET_DEFAULT} }
+
+
+/*
+ * Storage Layout
+ */
+
+/* This symbol was previously not mentioned, so apparently the tahoe
+ is little-endian for bits, or else doesn't care. */
+#define BITS_BIG_ENDIAN 0
+
+/* tahoe uses a big endian byte order */
+
+#define BYTES_BIG_ENDIAN 1
+
+/* tahoe uses a big endian word order */
+
+#define WORDS_BIG_ENDIAN 1
+
+/* standard byte size is usable on tahoe */
+
+#define BITS_PER_UNIT 8
+
+/* longs on the tahoe are 4 byte groups */
+
+#define BITS_PER_WORD 32
+
+/* from the last two params we get 4 bytes per word */
+
+#define UNITS_PER_WORD 4
+
+/* addresses are 32 bits (one word) */
+
+#define POINTER_SIZE 32
+
+/* all parameters line up on 32 boundaries */
+
+#define PARM_BOUNDARY 32
+
+/* stack should line up on 32 boundaries */
+
+#define STACK_BOUNDARY 32
+
+/* line functions up on 32 bits */
+
+#define FUNCTION_BOUNDARY 32
+
+/* the biggest alignment the tahoe needs in 32 bits */
+
+#define BIGGEST_ALIGNMENT 32
+
+/* we have to align after an 'int : 0' in a structure */
+
+#define EMPTY_FIELD_BOUNDARY 32
+
+#ifdef HCX_UX
+/* structures must be made of full words */
+
+#define STRUCTURE_SIZE_BOUNDARY 32
+#else
+/* structures must be made of full bytes */
+
+#define STRUCTURE_SIZE_BOUNDARY 8
+#endif
+
+/* tahoe is picky about data alignment */
+
+#define STRICT_ALIGNMENT 1
+
+/* keep things standard with pcc */
+
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* this section is borrowed from the vax version since the */
+/* formats are the same in both of the architectures */
+
+#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
+ if (OVERFLOW) \
+ (D) = 1.7014117331926443e+38; \
+ else if ((MODE) == SFmode) \
+ { \
+ if ((D) > 1.7014117331926443e+38) \
+ (OVERFLOW) = 1, (D) = 1.7014117331926443e+38; \
+ else if ((D) < -1.7014117331926443e+38) \
+ (OVERFLOW) = 1, (D) = -1.7014117331926443e+38; \
+ else if (((D) > 0) && ((D) < 2.9387358770557188e-39)) \
+ (OVERFLOW) = 1, (D) = 0.0; \
+ else if (((D) < 0) && ((D) > -2.9387358770557188e-39)) \
+ (OVERFLOW) = 1, (D) = 0.0; \
+ }
+
+
+/*
+ * Register Usage
+ */
+
+/* define 15 general regs plus one for the floating point reg (FPP) */
+
+#define FIRST_PSEUDO_REGISTER 17
+
+/* let the compiler know what the fp, sp and pc are */
+
+#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}
+
+/* lots of regs aren't guaranteed to return from a call. The FPP reg */
+/* must be included in these since it can't be saved by the reg mask */
+
+#define CALL_USED_REGISTERS {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}
+
+/* A single fp reg can handle any type of float.
+ CPU regs hold just 32 bits. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ (REGNO != 16 ? ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) \
+ : GET_MODE_NUNITS ((MODE)))
+
+/* any mode greater than 4 bytes (doubles) can only go in an even regs */
+/* and the FPP can only hold SFmode and DFmode */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ (REGNO != 16 \
+ ? (GET_MODE_UNIT_SIZE (MODE) <= 4 ? 1 : (REGNO % 2 - 1)) \
+ : ((MODE) == SFmode || (MODE) == DFmode \
+ || (MODE) == SCmode || (MODE) == DCmode))
+
+/* if mode1 or mode2, but not both, are doubles then modes cannot be tied */
+
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ (((MODE1) == DFmode || (MODE1) == DCmode) \
+ == ((MODE2) == DFmode || (MODE2) == DCmode))
+
+/* return nonzero if register variable of mode MODE is not
+ a priori a bad idea. Used only if defined. */
+#define MODE_OK_FOR_USERVAR(MODE) \
+ ((MODE) == SImode)
+
+/* the program counter is reg 15 */
+
+#define PC_REGNUM 15
+
+/* the stack pointer is reg 14 */
+
+#define STACK_POINTER_REGNUM 14
+
+/* the frame pointer is reg 13 */
+
+#define FRAME_POINTER_REGNUM 13
+
+/* tahoe does require an fp */
+
+#define FRAME_POINTER_REQUIRED 1
+
+/* since tahoe doesn't have a argument pointer, make it the fp */
+
+#define ARG_POINTER_REGNUM 13
+
+/* this isn't currently used since C doesn't support this feature */
+
+#define STATIC_CHAIN_REGNUM 0
+
+/* we'll use reg 1 for structure passing cause the destination */
+/* of the eventual movblk requires it to be there anyway. */
+
+#define STRUCT_VALUE_REGNUM 1
+
+
+/*
+ * Register Classes
+ */
+
+/* tahoe has two types of regs. GENERAL_REGS are all the regs up */
+/* to number 15. FPP_REG is the special floating point processor */
+/* register class (only one reg). */
+
+enum reg_class {NO_REGS,GENERAL_REGS,FPP_REG,ALL_REGS,LIM_REG_CLASSES};
+
+/* defines the number of reg classes. */
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* this defines what the classes are officially named for debugging */
+
+#define REG_CLASS_NAMES \
+ {"NO_REGS","GENERAL_REGS","FPP_REG","ALL_REGS"}
+
+/* set general regs to be the first 16 regs and the fpp reg to be 17th */
+
+#define REG_CLASS_CONTENTS {0,0xffff,0x10000,0x1ffff}
+
+/* register class for the fpp reg is FPP_REG, all others are GENERAL_REGS */
+
+#define REGNO_REG_CLASS(REGNO) (REGNO == 16 ? FPP_REG : GENERAL_REGS)
+
+/* only general registers can be used as a base reg */
+
+#define BASE_REG_CLASS GENERAL_REGS
+
+/* only general registers can be used to index */
+
+#define INDEX_REG_CLASS GENERAL_REGS
+
+/* 'a' as a constraint in the md file means the FFP_REG class */
+
+#define REG_CLASS_FROM_LETTER(C) (C == 'a' ? FPP_REG : NO_REGS)
+
+/* any general reg but the fpp can be a base reg */
+
+#define REGNO_OK_FOR_BASE_P(regno) \
+((regno) < FIRST_PSEUDO_REGISTER - 1 || reg_renumber[regno] >= 0)
+
+/* any general reg except the pc and fpp can be an index reg */
+
+#define REGNO_OK_FOR_INDEX_P(regno) \
+((regno) < FIRST_PSEUDO_REGISTER - 2 || reg_renumber[regno] >= 0)
+
+/* if your loading a floating point constant, it can't be done */
+/* through a register. Force it to be a memory constant. */
+
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+ ((GET_CODE (X) == CONST_DOUBLE) ? NO_REGS : CLASS)
+
+/* for the fpp reg, all modes fit; for any others, you need two for doubles */
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (CLASS != FPP_REG ? ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : 1)
+
+/* we don't define any special constant sizes so all should fail */
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) 0
+
+/* we don't define any special double sizes so all should fail */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
+
+
+/*
+ * Describing Stack Layout
+ */
+
+/* tahoe stack grows from high to low memory */
+
+#define STACK_GROWS_DOWNWARD
+
+/* Define this if longjmp restores from saved registers
+ rather than from what setjmp saved. */
+#define LONGJMP_RESTORE_FROM_STACK
+
+/* tahoe call frames grow from high to low memory on the stack */
+
+#define FRAME_GROWS_DOWNWARD
+
+/* the tahoe fp points to the *top* of the frame instead of the */
+/* bottom, so we have to make this offset a constant large enough */
+/* to jump over the biggest frame possible. */
+
+#define STARTING_FRAME_OFFSET -52
+
+/* tahoe always pushes 4 bytes unless it's a double in which case */
+/* it pushes a full 8 bytes. */
+
+#define PUSH_ROUNDING(BYTES) (BYTES <= 4 ? 4 : 8)
+
+/* the first parameter in a function is at the fp + 4 */
+
+#define FIRST_PARM_OFFSET(FNDECL) 4
+
+/* the tahoe return function takes care of everything on the stack */
+
+#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) (SIZE)
+
+/* function values for all types are returned in register 0 */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ gen_rtx (REG, TYPE_MODE (VALTYPE), 0)
+
+/* library routines also return things in reg 0 */
+
+#define LIBCALL_VALUE(MODE) gen_rtx (REG, MODE, 0)
+
+/* Tahoe doesn't return structures in a reentrant way */
+
+#define PCC_STATIC_STRUCT_RETURN
+
+/* we only return values from a function in reg 0 */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
+
+/* we never pass args through a register */
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0
+
+/* int is fine to hold the argument summary in FUNCTION_ARG */
+
+#define CUMULATIVE_ARGS int
+
+/* we just set CUM to 0 before the FUNCTION_ARG call. No matter what */
+/* we make it, FUNCTION_ARG will return 0 anyway */
+
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \
+ ((CUM) = 0)
+
+/* all modes push their size rounded to the nearest word boundary */
+/* except block which is the size of the block rounded up */
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ ((CUM) += ((MODE) != BLKmode \
+ ? (GET_MODE_SIZE (MODE) + 3) & ~3 \
+ : (int_size_in_bytes (TYPE) + 3) & ~3))
+
+/* this is always false since we never pass params in regs */
+
+#define FUNCTION_ARG_REGNO_P(N) 0
+
+/* this code calculates the register entry mask and sets up */
+/* the stack pointer for the function. The stack is set down */
+/* far enough from the fp to jump over any push regs and local */
+/* vars. This is a problem since the tahoe has the fp pointing */
+/* to the top of the frame and the compiler must know the off- */
+/* set off the fp to the local vars. */
+
+#define FUNCTION_PROLOGUE(FILE, SIZE) \
+{ register int regno; \
+ register int mask = 0; \
+ extern char call_used_regs[]; \
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER-1; regno++) \
+ if (regs_ever_live[regno] && !call_used_regs[regno]) \
+ mask |= 1 << regno; \
+ fprintf (FILE, "\t.word 0x%x\n", mask); \
+ if (SIZE != 0) fprintf (FILE, "\tsubl3 $%d,fp,sp\n", (SIZE) - STARTING_FRAME_OFFSET); }
+
+/* Zero out global variable in case it was used in this function. */
+#define FUNCTION_EPILOGUE(FILE, SIZE) \
+{ extern rtx tahoe_reg_conversion_loc; \
+ tahoe_reg_conversion_loc = 0; \
+}
+
+#ifdef HCX_UX
+
+/* to call the profiler, the address of the counter var is placed */
+/* on the stack and then passed into mcount this way */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tpushal LP%d\n\tcallf $8,mcount\n", (LABELNO));
+
+#else
+
+/* to call the profiler, push the variable value onto the stack */
+/* and call mcount like a regular function. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tpushl $LP%d\n\tcallf $8,mcount\n", (LABELNO));
+
+#endif
+
+/* all stack handling at the end of a function is handled by the */
+/* return command. */
+
+#define EXIT_IGNORE_STACK 1
+
+/*
+ * Library Subroutine Names
+ */
+
+/* udiv is a valid C library routine in libc.a, so we call that */
+
+#define UDIVSI3_LIBCALL "*udiv"
+
+/* urem is a valid C library routine in libc.a, so we call that */
+/* but not so on hcx/ux */
+
+#ifdef HCX_UX
+#undef UMODSI3_LIBCALL
+#else
+#define UMODSI3_LIBCALL "*urem"
+#endif
+
+
+/*
+ * Addressing Modes
+ */
+
+/* constant addresses can be treated exactly the same as normal constants */
+
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
+ || GET_CODE (X) == HIGH)
+
+/* we can have as many as two regs in any given address */
+
+#define MAX_REGS_PER_ADDRESS 2
+
+/* The following is all the code for GO_IF_LEGITIMATE_ADDRESS */
+/* most of this taken directly from the vax tm file since the */
+/* tahoe and vax addressing modes are nearly identical. */
+
+/* Is x an indirectable address? */
+
+#define INDIRECTABLE_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)) \
+ && CONSTANT_ADDRESS_P (XEXP (X, 1))))
+
+/* If x is a non-indexed-address, go to ADDR. */
+
+#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \
+{ register rtx xfoob = (X); \
+ if (GET_CODE (xfoob) == REG) goto ADDR; \
+ if (INDIRECTABLE_ADDRESS_P (xfoob)) goto ADDR; \
+ xfoob = XEXP (X, 0); \
+ if (GET_CODE (X) == MEM && INDIRECTABLE_ADDRESS_P (xfoob)) \
+ goto ADDR; \
+ if ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \
+ && GET_CODE (xfoob) == REG && REGNO (xfoob) == 14) \
+ goto ADDR; }
+
+/* Is PROD an index term in mode MODE. */
+
+#define INDEX_TERM_P(PROD, MODE) \
+(GET_MODE_SIZE (MODE) == 1 \
+ ? (GET_CODE (PROD) == REG && REG_OK_FOR_BASE_P (PROD)) \
+ : (GET_CODE (PROD) == MULT \
+ && \
+ (xfoo0 = XEXP (PROD, 0), xfoo1 = XEXP (PROD, 1), \
+ ((GET_CODE (xfoo0) == CONST_INT \
+ && INTVAL (xfoo0) == GET_MODE_SIZE (MODE) \
+ && GET_CODE (xfoo1) == REG \
+ && REG_OK_FOR_INDEX_P (xfoo1)) \
+ || \
+ (GET_CODE (xfoo1) == CONST_INT \
+ && INTVAL (xfoo1) == GET_MODE_SIZE (MODE) \
+ && GET_CODE (xfoo0) == REG \
+ && REG_OK_FOR_INDEX_P (xfoo0))))))
+
+/* Is the addition to the index a reg? */
+
+#define GO_IF_REG_PLUS_INDEX(X, MODE, ADDR) \
+{ register rtx xfooa; \
+ if (GET_CODE (X) == PLUS) \
+ { if (GET_CODE (XEXP (X, 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && (xfooa = XEXP (X, 1), \
+ INDEX_TERM_P (xfooa, MODE))) \
+ goto ADDR; \
+ if (GET_CODE (XEXP (X, 1)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 1)) \
+ && (xfooa = XEXP (X, 0), \
+ INDEX_TERM_P (xfooa, MODE))) \
+ goto ADDR; } }
+
+/* Is the rtx X a valid memory address for operand of mode MODE? */
+/* If it is, go to ADDR */
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+{ register rtx xfoo, xfoo0, xfoo1; \
+ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \
+ if (GET_CODE (X) == PLUS) \
+ { xfoo = XEXP (X, 0); \
+ if (INDEX_TERM_P (xfoo, MODE)) \
+ { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 1), ADDR); } \
+ xfoo = XEXP (X, 1); \
+ if (INDEX_TERM_P (xfoo, MODE)) \
+ { GO_IF_NONINDEXED_ADDRESS (XEXP (X, 0), ADDR); } \
+ if (CONSTANT_ADDRESS_P (XEXP (X, 0))) \
+ { if (GET_CODE (XEXP (X, 1)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 1))) \
+ goto ADDR; \
+ GO_IF_REG_PLUS_INDEX (XEXP (X, 1), MODE, ADDR); } \
+ if (CONSTANT_ADDRESS_P (XEXP (X, 1))) \
+ { if (GET_CODE (XEXP (X, 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 0))) \
+ goto ADDR; \
+ GO_IF_REG_PLUS_INDEX (XEXP (X, 0), MODE, ADDR); } } }
+
+/* Register 16 can never be used for index or base */
+
+#ifndef REG_OK_STRICT
+#define REG_OK_FOR_INDEX_P(X) (REGNO(X) != 16)
+#define REG_OK_FOR_BASE_P(X) (REGNO(X) != 16)
+#else
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+#endif
+
+/* Addressing is too simple to allow optimizing here */
+
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) {}
+
+/* Post_inc and pre_dec always adds 4 */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
+ { if (GET_CODE(ADDR) == POST_INC || GET_CODE(ADDR) == PRE_DEC) \
+ goto LABEL; \
+ if (GET_CODE (ADDR) == PLUS) \
+ { if (CONSTANT_ADDRESS_P (XEXP (ADDR, 0)) \
+ && GET_CODE (XEXP (ADDR, 1)) == REG); \
+ else if (CONSTANT_ADDRESS_P (XEXP (ADDR, 1)) \
+ && GET_CODE (XEXP (ADDR, 0)) == REG); \
+ else goto LABEL; }}
+
+/* Double's are not legitimate as immediate operands */
+
+#define LEGITIMATE_CONSTANT_P(X) \
+ (GET_CODE (X) != CONST_DOUBLE)
+
+
+/*
+ * Miscellaneous Parameters
+ */
+
+/* the elements in the case jump table are all words */
+
+#define CASE_VECTOR_MODE HImode
+
+/* each of the table elements in a case are relative to the jump address */
+
+#define CASE_VECTOR_PC_RELATIVE
+
+/* tahoe case instructions just fall through to the next instruction */
+/* if not satisfied. It doesn't support a default action */
+
+#define CASE_DROPS_THROUGH
+
+/* the standard answer is given here and work ok */
+
+#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+
+/* in a general div case, it's easiest to use TRUNC_DIV_EXPR */
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* the standard seems to be leaving char's as signed so we left it */
+/* this way even though we think they should be unsigned! */
+
+#define DEFAULT_SIGNED_CHAR 1
+
+/* the most we can move without cutting down speed is 4 bytes */
+
+#define MOVE_MAX 4
+
+/* our int is 32 bits */
+
+#define INT_TYPE_SIZE 32
+
+/* byte access isn't really slower than anything else */
+
+#define SLOW_BYTE_ACCESS 0
+
+/* zero extension is more than one instruction so try to avoid it */
+
+#define SLOW_ZERO_EXTEND
+
+/* any bits higher than the low 4 are ignored in the shift count */
+/* so don't bother zero extending or sign extending them */
+
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* we don't need to officially convert from one fixed type to another */
+/* in order to use it as that type. We can just assume it's the same */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* pass chars as ints */
+
+#define PROMOTE_PROTOTYPES
+
+/* pointers can be represented by an si mode expression */
+
+#define Pmode SImode
+
+/* function addresses are made by specifying a byte address */
+
+#define FUNCTION_MODE QImode
+
+/* Define this if addresses of constant functions
+ shouldn't be put through pseudo regs where they can be cse'd.
+ On the tahoe a call with a constant address is much faster than one with a
+ register. */
+
+#define NO_FUNCTION_CSE
+
+/* specify the costs of various sorts of constants,
+ and also indicate that multiplication is cheap on this machine. */
+
+#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
+ case CONST_INT: \
+ /* Constant zero is super cheap due to clr instruction. */ \
+ if (RTX == const0_rtx) return 0; \
+ if ((unsigned) INTVAL (RTX) < 077) return 1; \
+ if (INTVAL (RTX) <= 127 && INTVAL (RTX) >= -128) return 2; \
+ case CONST: \
+ case LABEL_REF: \
+ case SYMBOL_REF: \
+ return 3; \
+ case CONST_DOUBLE: \
+ return 5; \
+ case MULT: \
+ total = 2;
+
+
+/*
+ * Condition Code Information
+ */
+
+/* Nonzero if the results of the previous comparison are
+ in the floating point condition code register. */
+
+#define CC_UNCHANGED 04000
+
+
+#define NOTICE_UPDATE_CC(EXP, INSN) \
+{ if (cc_status.flags & CC_UNCHANGED) \
+ /* Happens for cvtld and a few other insns. */ \
+ cc_status.flags &= ~CC_UNCHANGED; \
+ else if (GET_CODE (EXP) == SET) \
+ { if (GET_CODE (SET_SRC (EXP)) == CALL) \
+ CC_STATUS_INIT; \
+ else if (GET_CODE (SET_DEST (EXP)) != PC) \
+ { cc_status.flags = 0; \
+ cc_status.value1 = SET_DEST (EXP); \
+ cc_status.value2 = SET_SRC (EXP); } } \
+ else if (GET_CODE (EXP) == PARALLEL \
+ && GET_CODE (XVECEXP (EXP, 0, 0)) == SET \
+ && GET_CODE (SET_DEST (XVECEXP (EXP, 0, 0))) != PC) \
+ { cc_status.flags = 0; \
+ cc_status.value1 = SET_DEST (XVECEXP (EXP, 0, 0)); \
+ cc_status.value2 = SET_SRC (XVECEXP (EXP, 0, 0)); } \
+ /* PARALLELs whose first element sets the PC are aob, sob insns. \
+ They do change the cc's. So drop through and forget the cc's. */ \
+ else 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)) \
+ cc_status.value2 = 0; \
+ if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM \
+ && cc_status.value2 \
+ && GET_CODE (cc_status.value2) == MEM) \
+ cc_status.value2 = 0; }
+/* Actual condition, one line up, should be that value2's address
+ depends on value1, but that is too much of a pain. */
+
+
+/*
+ * Output of Assembler Code
+ */
+
+/* print which tahoe version compiled this code and print a directive */
+/* to the gnu assembler to say that the following is normal assembly */
+
+#ifdef HCX_UX
+#define ASM_FILE_START(FILE) \
+{ fprintf (FILE, "#gcc hcx 1.0\n\n"); \
+ output_file_directive ((FILE), main_input_filename);} while (0)
+#else
+#define ASM_FILE_START(FILE) fprintf (FILE, "#gcc tahoe 1.0\n#NO_APP\n");
+#endif
+
+/* the instruction that turns on the APP for the gnu assembler */
+
+#define ASM_APP_ON "#APP\n"
+
+/* the instruction that turns off the APP for the gnu assembler */
+
+#define ASM_APP_OFF "#NO_APP\n"
+
+/* what to output before read-only data. */
+
+#define TEXT_SECTION_ASM_OP ".text"
+
+/* what to output before writable data. */
+
+#define DATA_SECTION_ASM_OP ".data"
+
+/* this is what we call each of the regs. notice that the FPP reg is */
+/* called "ac". This should never get used due to the way we've set */
+/* up FPP instructions in the md file. But we call it "ac" here to */
+/* fill the list. */
+
+#define REGISTER_NAMES \
+{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \
+ "r9", "r10", "r11", "r12", "fp", "sp", "pc", "ac"}
+
+#ifdef HCX_UX
+/* allow generation of sdb info in the assembly */
+#define SDB_DEBUGGING_INFO
+#else
+/* allow generation of dbx info in the assembly */
+
+#define DBX_DEBUGGING_INFO
+
+/* our dbx doesn't support this */
+
+#define DBX_NO_XREFS
+
+/* we don't want symbols broken up */
+
+#define DBX_CONTIN_LENGTH 0
+
+/* this'll really never be used, but we'll leave it at this */
+
+#define DBX_CONTIN_CHAR '?'
+
+#endif /* HCX_UX */
+
+/* registers are called the same thing in dbx anything else */
+/* This is necessary even if we generate SDB output */
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* labels are the label followed by a colon and a newline */
+/* must be a statement, so surround it in a null loop */
+
+#define ASM_OUTPUT_LABEL(FILE,NAME) \
+ do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
+
+/* use the .globl directive to make labels global for the linker */
+
+#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
+ do { fputs (".globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
+
+/* output a label by appending an underscore to it */
+
+#define ASM_OUTPUT_LABELREF(FILE,NAME) \
+ fprintf (FILE, "_%s", NAME)
+
+/* use the standard format for printing internal labels */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, "%s%d:\n", PREFIX, NUM)
+
+/* a * is used for label indirection in unix assembly */
+
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*%s%d", PREFIX, NUM)
+
+/* outputting a double is easy cause we only have one kind */
+
+#ifdef HCX_UX
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
+ fprintf (FILE, "\t.double 0d%.20e\n", (VALUE))
+#else
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
+{ \
+ union { int i[2]; double d;} temp; \
+ temp.d = (VALUE); \
+ if (TARGET_HEX_FLOAT) \
+ fprintf ((FILE), "\t.long 0x%x,0x%x # %.20e\n", \
+ temp.i[0], temp.i[1], temp.d); \
+ else \
+ fprintf (FILE, "\t.dfloat 0d%.20e\n", temp.d); \
+}
+#endif
+
+/* This is how to output an assembler line defining a `float' constant. */
+
+#ifdef HCX_UX
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+ fprintf (FILE, "\t.float 0f%.20e\n", (VALUE))
+#else
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+{ \
+ union { int i; float f;} temp; \
+ temp.f = (float) (VALUE); \
+ if (TARGET_HEX_FLOAT) \
+ fprintf ((FILE), "\t.long 0x%x # %.20e\n", \
+ temp.i, temp.f); \
+ else \
+ fprintf (FILE, "\t.float 0f%.20e\n", temp.f); \
+}
+#endif
+
+/* 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"))
+
+#ifdef HCX_UX
+/* This is how to output an assembler line for an ASCII string. */
+
+#define ASM_OUTPUT_ASCII(FILE, p, size) \
+do { register int i; \
+ fprintf ((FILE), "\t.ascii \""); \
+ for (i = 0; i < (size); i++) \
+ { \
+ register int c = (p)[i]; \
+ if (c == '\'' || c == '\\') \
+ putc ('\\', (FILE)); \
+ if (c >= ' ' && c < 0177 && c != '\"') \
+ putc (c, (FILE)); \
+ else \
+ { \
+ fprintf ((FILE), "\\%03o", c); \
+ } \
+ } \
+ fprintf ((FILE), "\"\n"); } while (0)
+#endif
+
+/* 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 the insn to push a register onto the stack */
+
+#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
+ fprintf (FILE, "\tpushl %s\n", reg_names[REGNO])
+
+/* this is the insn to pop a register from the stack */
+
+#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
+ fprintf (FILE, "\tmovl (sp)+,%s\n", reg_names[REGNO])
+
+/* this is required even thought tahoe doesn't support it */
+/* cause the C code expects it to be defined */
+
+#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. */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+ fprintf (FILE, "\t.word L%d-L%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. */
+
+#ifdef HCX_UX
+#define CASE_ALIGNMENT 2
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG))
+#else
+#define CASE_ALIGNMENT 1
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ LOG ? fprintf (FILE, "\t.align %d\n", (LOG)) : 0
+#endif
+
+/* This is how to skip over some space */
+
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t.space %u\n", (SIZE))
+
+/* This defines common variables across files */
+
+#ifdef HCX_UX
+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
+( fputs (".comm ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u\n", (SIZE)))
+#else
+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
+( fputs (".comm ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u\n", (ROUNDED)))
+#endif
+
+/* This says how to output an assembler line
+ to define a local common symbol. */
+
+#ifdef HCX_UX
+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
+( fputs ("\t.bss ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u,4\n", (SIZE),(ROUNDED)))
+#else
+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \
+( fputs (".lcomm ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u\n", (ROUNDED)))
+#endif
+
+/* code to generate a label */
+
+#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'.
+ On the Vax, the only code used is `#', indicating that either
+ `d' or `g' should be printed, depending on whether we're using dfloat
+ or gfloat. */
+/* Print an operand. Some difference from the vax code,
+ since the tahoe can't support immediate floats and doubles.
+
+ %@ means print the proper alignment operand for aligning after a casesi.
+ This depends on the assembler syntax.
+ This is 1 for our assembler, since .align is logarithmic.
+
+ %s means the number given is supposed to be a shift value, but on
+ the tahoe it should be converted to a number that can be used as a
+ multiplicative constant (cause multiplication is a whole lot faster
+ than shifting). So make the number 2^n instead. */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+ ((CODE) == '@')
+
+#define PRINT_OPERAND(FILE, X, CODE) \
+{ if (CODE == '@') \
+ putc ('0' + CASE_ALIGNMENT, FILE); \
+ else if (CODE == 's') \
+ fprintf (FILE, "$%d", 1 << INTVAL(X)); \
+ else if (GET_CODE (X) == REG) \
+ fprintf (FILE, "%s", reg_names[REGNO (X)]); \
+ else if (GET_CODE (X) == MEM) \
+ output_address (XEXP (X, 0)); \
+ else { putc ('$', FILE); output_addr_const (FILE, X); }}
+
+/* When the operand is an address, call print_operand_address to */
+/* do the work from output-tahoe.c. */
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
+ print_operand_address (FILE, ADDR)
+
+/* This is for G++ */
+
+#define CRT0_DUMMIES
+#define DOT_GLOBAL_START
+#ifdef HCX_UX
+#define NO_GNU_LD /* because of COFF format */
+#define LINK_SPEC "-L/usr/staff/lib"
+#endif
diff --git a/gnu/usr.bin/gcc/config/tahoe/tahoe.md b/gnu/usr.bin/gcc/config/tahoe/tahoe.md
new file mode 100644
index 00000000000..eaa92d05d5e
--- /dev/null
+++ b/gnu/usr.bin/gcc/config/tahoe/tahoe.md
@@ -0,0 +1,2113 @@
+;; Machine description for GNU compiler, Tahoe version
+;; Copyright (C) 1989, 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.
+
+
+; File: tahoe.md
+;
+; Original port made at the University of Buffalo by Devon Bowen,
+; Dale Wiles and Kevin Zachmann.
+;
+; Piet van Oostrum (piet@cs.ruu.nl) made changes for HCX/UX, fixed
+; some bugs and made some improvements (hopefully).
+;
+; Mail bugs reports or fixes to: gcc@cs.buffalo.edu
+
+
+; movdi must call the output_move_double routine to move it around since
+; the tahoe doesn't efficiently support 8 bit moves.
+
+(define_insn "movdi"
+ [(set (match_operand:DI 0 "general_operand" "=g")
+ (match_operand:DI 1 "general_operand" "g"))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return output_move_double (operands);
+}")
+
+
+; the trick in the movsi is accessing the contents of the sp register. The
+; tahoe doesn't allow you to access it directly so you have to access the
+; address of the top of the stack instead.
+
+(define_insn "movsi"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (match_operand:SI 1 "general_operand" "g"))]
+ ""
+ "*
+{
+ rtx link;
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ && ! INSN_DELETED_P (XEXP (link, 0))
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ && no_labels_between_p (XEXP (link, 0), insn)
+ /* Make sure the reg hasn't been clobbered. */
+ && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+ return \"incl %0\";
+ if (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST)
+ {
+ if (push_operand (operands[0], SImode))
+ return \"pushab %a1\";
+ return \"movab %a1,%0\";
+ }
+ if (operands[1] == const0_rtx)
+ return \"clrl %0\";
+ if (push_operand (operands[0], SImode))
+ return \"pushl %1\";
+ if (GET_CODE(operands[1]) == REG && REGNO(operands[1]) == 14)
+ return \"moval (sp),%0\";
+ return \"movl %1,%0\";
+}")
+
+
+(define_insn "movhi"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (match_operand:HI 1 "general_operand" "g"))]
+ ""
+ "*
+{
+ rtx link;
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ && ! INSN_DELETED_P (XEXP (link, 0))
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ && no_labels_between_p (XEXP (link, 0), insn)
+ /* Make sure the reg hasn't been clobbered. */
+ && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+ return \"incw %0\";
+ if (operands[1] == const0_rtx)
+ return \"clrw %0\";
+ return \"movw %1,%0\";
+}")
+
+
+(define_insn "movqi"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (match_operand:QI 1 "general_operand" "g"))]
+ ""
+ "*
+{
+ if (operands[1] == const0_rtx)
+ return \"clrb %0\";
+ return \"movb %1,%0\";
+}")
+
+
+; movsf has three cases since they can move from one place to another
+; or to/from the fpp and since different instructions are needed for
+; each case. The fpp related instructions don't set the flags properly.
+
+(define_insn "movsf"
+ [(set (match_operand:SF 0 "general_operand" "=g,=a,=g")
+ (match_operand:SF 1 "general_operand" "g,g,a"))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ switch (which_alternative)
+ {
+ case 0: return \"movl %1,%0\";
+ case 1: return \"ldf %1\";
+ case 2: return \"stf %0\";
+ }
+}")
+
+
+; movdf has a number of different cases. If it's going to or from
+; the fpp, use the special instructions to do it. If not, use the
+; output_move_double function.
+
+(define_insn "movdf"
+ [(set (match_operand:DF 0 "general_operand" "=a,=g,?=g")
+ (match_operand:DF 1 "general_operand" "g,a,g"))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ switch (which_alternative)
+ {
+ case 0:
+ return \"ldd %1\";
+ case 1:
+ if (push_operand (operands[0], DFmode))
+ return \"pushd\";
+ else
+ return \"std %0\";
+ case 2:
+ return output_move_double (operands);
+ }
+}")
+
+
+;========================================================================
+; The tahoe has the following semantics for byte (and similar for word)
+; operands: if the operand is a register or immediate, it takes the full 32
+; bit operand, if the operand is memory, it sign-extends the byte. The
+; operation is performed on the 32 bit values. If the destination is a
+; register, the full 32 bit result is stored, if the destination is memory,
+; of course only the low part is stored. The condition code is based on the
+; 32 bit operation. Only on the movz instructions the byte from memory is
+; zero-extended rather than sign-extended.
+
+; This means that for arithmetic instructions we can use addb etc. to
+; perform a long add from a signed byte from memory to a register. Of
+; course this would also work for logical operations, but that doesn't seem
+; very useful.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "addb3 %1,%2,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "nonmemory_operand" "%ri")
+ (sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"addb2 %2,%0\";
+ return \"addb3 %1,%2,%0\";
+}")
+
+; We can also consider the result to be a half integer
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (plus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
+ (sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "addb3 %1,%2,%0")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (plus:HI (match_operand:HI 1 "nonmemory_operand" "%ri")
+ (sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"addb2 %2,%0\";
+ return \"addb3 %1,%2,%0\";
+}")
+
+; The same applies to words (HI)
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
+ ""
+ "addw3 %1,%2,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "nonmemory_operand" "%ri")
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"addw2 %2,%0\";
+ return \"addw3 %1,%2,%0\";
+}")
+
+; ======================= Now for subtract ==============================
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "subb3 %2,%1,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "nonmemory_operand" "ri")
+ (sign_extend:SI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"subb2 %2,%0\";
+ return \"subb3 %2,%1,%0\";
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))
+ (match_operand:SI 2 "nonmemory_operand" "ri")))]
+ ""
+ "subb3 %2,%1,%0")
+
+; We can also consider the result to be a half integer
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (minus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
+ (sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "subb3 %2,%1,%0")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (minus:HI (match_operand:HI 1 "nonmemory_operand" "%ri")
+ (sign_extend:HI (match_operand:QI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"subb2 %2,%0\";
+ return \"subb3 %2,%1,%0\";
+}")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (minus:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))
+ (match_operand:HI 2 "nonmemory_operand" "ri")))]
+ ""
+ "subb3 %2,%1,%0")
+
+; The same applies to words (HI)
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
+ ""
+ "subw3 %2,%1,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "nonmemory_operand" "ri")
+ (sign_extend:SI (match_operand:HI 2 "memory_operand" "m"))))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"subw2 %2,%0\";
+ return \"subw3 %2,%1,%0\";
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))
+ (match_operand:SI 2 "nonmemory_operand" "ri")))]
+ ""
+ "subw3 %2,%1,%0")
+
+; ======================= Now for neg ==============================
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
+ ""
+ "mnegb %1,%0")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (neg:HI (sign_extend:HI (match_operand:QI 1 "memory_operand" "m"))))]
+ ""
+ "mnegb %1,%0")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
+ ""
+ "mnegw %1,%0")
+
+;========================================================================
+
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (plus:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"incl %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -1)
+ return \"decl %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subl2 $%n2,%0\";
+ return \"addl2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"addl2 %1,%0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && GET_CODE (operands[1]) == REG)
+ {
+ if (push_operand (operands[0], SImode))
+ return \"pushab %c2(%1)\";
+ return \"movab %c2(%1),%0\";
+ }
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subl3 $%n2,%1,%0\";
+ return \"addl3 %1,%2,%0\";
+}")
+
+
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (plus:HI (match_operand:HI 1 "general_operand" "g")
+ (match_operand:HI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"incw %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -1)
+ return \"decw %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subw2 $%n2,%0\";
+ return \"addw2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"addw2 %1,%0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subw3 $%n2,%1,%0\";
+ return \"addw3 %1,%2,%0\";
+}")
+
+
+(define_insn "addqi3"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (plus:QI (match_operand:QI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"incb %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -1)
+ return \"decb %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subb2 $%n2,%0\";
+ return \"addb2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"addb2 %1,%0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned) (- INTVAL (operands[2])) < 64)
+ return \"subb3 $%n2,%1,%0\";
+ return \"addb3 %1,%2,%0\";
+}")
+
+; addsf3 can only add into the fpp register since the fpp is treated
+; as a separate unit in the machine. It also doesn't set the flags at
+; all.
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (plus:SF (match_operand:SF 1 "register_operand" "%0")
+ (match_operand:SF 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"addf %2\";
+}")
+
+
+; adddf3 can only add into the fpp reg since the fpp is treated as a
+; separate entity. Doubles can only be read from a register or memory
+; since a double is not an immediate mode. Flags are not set by this
+; instruction.
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (plus:DF (match_operand:DF 1 "register_operand" "%0")
+ (match_operand:DF 2 "general_operand" "rm")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"addd %2\";
+}")
+
+
+; Subtraction from the sp (needed by the built in alloc function) needs
+; to be different since the sp cannot be directly read on the tahoe.
+; If it's a simple constant, you just use displacement. Otherwise, you
+; push the sp, and then do the subtraction off the stack.
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (minus:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"decl %0\";
+ if (GET_CODE(operands[0]) == REG && REGNO(operands[0]) == 14)
+ {
+ if (GET_CODE(operands[2]) == CONST_INT)
+ return \"movab %n2(sp),sp\";
+ else
+ return \"pushab (sp)\;subl3 %2,(sp),sp\";
+ }
+ return \"subl2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[1], operands[2]))
+ return \"clrl %0\";
+ return \"subl3 %2,%1,%0\";
+}")
+
+
+(define_insn "subhi3"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (minus:HI (match_operand:HI 1 "general_operand" "g")
+ (match_operand:HI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"decw %0\";
+ return \"subw2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[1], operands[2]))
+ return \"clrw %0\";
+ return \"subw3 %2,%1,%0\";
+}")
+
+
+(define_insn "subqi3"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (minus:QI (match_operand:QI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (operands[2] == const1_rtx)
+ return \"decb %0\";
+ return \"subb2 %2,%0\";
+ }
+ if (rtx_equal_p (operands[1], operands[2]))
+ return \"clrb %0\";
+ return \"subb3 %2,%1,%0\";
+}")
+
+
+; subsf3 can only subtract into the fpp accumulator due to the way
+; the fpp reg is limited by the instruction set. This also doesn't
+; bother setting up flags.
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (minus:SF (match_operand:SF 1 "register_operand" "0")
+ (match_operand:SF 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"subf %2\";
+}")
+
+
+; subdf3 is set up to subtract into the fpp reg due to limitations
+; of the fpp instruction set. Doubles can not be immediate. This
+; instruction does not set the flags.
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (minus:DF (match_operand:DF 1 "register_operand" "0")
+ (match_operand:DF 2 "general_operand" "rm")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"subd %2\";
+}")
+
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (mult:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"mull2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"mull2 %1,%0\";
+ return \"mull3 %1,%2,%0\";
+}")
+
+
+; mulsf3 can only multiply into the fpp accumulator due to limitations
+; of the fpp. It also does not set the condition codes properly.
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (mult:SF (match_operand:SF 1 "register_operand" "%0")
+ (match_operand:SF 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"mulf %2\";
+}")
+
+
+; muldf3 can only multiply into the fpp reg since the fpp is limited
+; from the rest. Doubles may not be immediate mode. This does not set
+; the flags like gcc would expect.
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (mult:DF (match_operand:DF 1 "register_operand" "%0")
+ (match_operand:DF 2 "general_operand" "rm")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"muld %2\";
+}")
+
+
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (div:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[1], operands[2]))
+ return \"movl $1,%0\";
+ if (operands[1] == const0_rtx)
+ return \"clrl %0\";
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == -1)
+ return \"mnegl %1,%0\";
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"divl2 %2,%0\";
+ return \"divl3 %2,%1,%0\";
+}")
+
+
+; divsf3 must divide into the fpp accumulator. Flags are not set by
+; this instruction, so they are cleared.
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (div:SF (match_operand:SF 1 "register_operand" "0")
+ (match_operand:SF 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"divf %2\";
+}")
+
+
+; divdf3 also must divide into the fpp reg so optimization isn't
+; possible. Note that doubles cannot be immediate. The flags here
+; are not set correctly so they must be ignored.
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (div:DF (match_operand:DF 1 "register_operand" "0")
+ (match_operand:DF 2 "general_operand" "rm")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"divd %2\";
+}")
+
+
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (and:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"andl2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"andl2 %1,%0\";
+ return \"andl3 %2,%1,%0\";
+}")
+
+
+
+(define_insn "andhi3"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (and:HI (match_operand:HI 1 "general_operand" "g")
+ (match_operand:HI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"andw2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"andw2 %1,%0\";
+ return \"andw3 %2,%1,%0\";
+}")
+
+
+(define_insn "andqi3"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (and:QI (match_operand:QI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"andb2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"andb2 %1,%0\";
+ return \"andb3 %2,%1,%0\";
+}")
+
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (ior:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"orl2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"orl2 %1,%0\";
+ return \"orl3 %2,%1,%0\";
+}")
+
+
+
+(define_insn "iorhi3"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (ior:HI (match_operand:HI 1 "general_operand" "g")
+ (match_operand:HI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"orw2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"orw2 %1,%0\";
+ return \"orw3 %2,%1,%0\";
+}")
+
+
+
+(define_insn "iorqi3"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (ior:QI (match_operand:QI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"orb2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"orb2 %1,%0\";
+ return \"orb3 %2,%1,%0\";
+}")
+
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (xor:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:SI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"xorl2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"xorl2 %1,%0\";
+ return \"xorl3 %2,%1,%0\";
+}")
+
+
+(define_insn "xorhi3"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (xor:HI (match_operand:HI 1 "general_operand" "g")
+ (match_operand:HI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"xorw2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"xorw2 %1,%0\";
+ return \"xorw3 %2,%1,%0\";
+}")
+
+
+(define_insn "xorqi3"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (xor:QI (match_operand:QI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"xorb2 %2,%0\";
+ if (rtx_equal_p (operands[0], operands[2]))
+ return \"xorb2 %1,%0\";
+ return \"xorb3 %2,%1,%0\";
+}")
+
+
+; shifts on the tahoe are expensive, try some magic first...
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (ashift:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (GET_CODE(operands[2]) == REG)
+ return \"mull3 ___shtab[%2],%1,%0\";
+ /* if (GET_CODE(operands[2]) == REG)
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"mull2 ___shtab[%2],%1\";
+ else
+ return \"mull3 ___shtab[%2],%1,%0\"; */
+ if (GET_CODE(operands[1]) == REG)
+ {
+ if (operands[2] == const1_rtx)
+ {
+ CC_STATUS_INIT;
+ return \"movaw 0[%1],%0\";
+ }
+ if (GET_CODE(operands[2]) == CONST_INT && INTVAL(operands[2]) == 2)
+ {
+ CC_STATUS_INIT;
+ return \"moval 0[%1],%0\";
+ }
+ }
+ if (GET_CODE(operands[2]) != CONST_INT || INTVAL(operands[2]) == 1)
+ return \"shal %2,%1,%0\";
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"mull2 %s2,%1\";
+ else
+ return \"mull3 %s2,%1,%0\";
+}")
+
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (ashiftrt:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "shar %2,%1,%0")
+
+
+; shifts are very expensive, try some magic first...
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (lshiftrt:SI (match_operand:SI 1 "general_operand" "g")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "shrl %2,%1,%0")
+
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (neg:SI (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "mnegl %1,%0")
+
+
+(define_insn "neghi2"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (neg:HI (match_operand:HI 1 "general_operand" "g")))]
+ ""
+ "mnegw %1,%0")
+
+
+(define_insn "negqi2"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (neg:QI (match_operand:QI 1 "general_operand" "g")))]
+ ""
+ "mnegb %1,%0")
+
+
+; negsf2 can only negate the value already in the fpp accumulator.
+; The value remains in the fpp accumulator. No flags are set.
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=a,=a")
+ (neg:SF (match_operand:SF 1 "register_operand" "a,g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ switch (which_alternative)
+ {
+ case 0: return \"negf\";
+ case 1: return \"lnf %1\";
+ }
+}")
+
+
+; negdf2 can only negate the value already in the fpp accumulator.
+; The value remains in the fpp accumulator. No flags are set.
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "register_operand" "=a,=a")
+ (neg:DF (match_operand:DF 1 "register_operand" "a,g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ switch (which_alternative)
+ {
+ case 0: return \"negd\";
+ case 1: return \"lnd %1\";
+ }
+}")
+
+
+; sqrtsf2 tahoe can calculate the square root of a float in the
+; fpp accumulator. The answer remains in the fpp accumulator. No
+; flags are set by this function.
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"sqrtf\";
+}")
+
+
+; ffssi2 tahoe instruction gives one less than gcc desired result for
+; any given input. So the increment is necessary here.
+
+(define_insn "ffssi2"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (ffs:SI (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "*
+{
+ if (push_operand(operands[0], SImode))
+ return \"ffs %1,%0\;incl (sp)\";
+ return \"ffs %1,%0\;incl %0\";
+}")
+
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (not:SI (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "mcoml %1,%0")
+
+
+(define_insn "one_cmplhi2"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (not:HI (match_operand:HI 1 "general_operand" "g")))]
+ ""
+ "mcomw %1,%0")
+
+
+(define_insn "one_cmplqi2"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (not:QI (match_operand:QI 1 "general_operand" "g")))]
+ ""
+ "mcomb %1,%0")
+
+
+; cmpsi works fine, but due to microcode problems, the tahoe doesn't
+; properly compare hi's and qi's. Leaving them out seems to be acceptable
+; to the compiler, so they were left out. Compares of the stack are
+; possible, though.
+
+; There are optimized cases possible, however. These follow first.
+
+(define_insn ""
+ [(set (cc0)
+ (compare (sign_extend:SI (match_operand:HI 0 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
+ ""
+ "cmpw %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (match_operand:SI 0 "nonmemory_operand" "ri")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
+ ""
+ "cmpw %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (sign_extend:SI (match_operand:HI 0 "memory_operand" "m"))
+ (match_operand:SI 1 "nonmemory_operand" "ri")))]
+ ""
+ "cmpw %0,%1")
+
+; zero-extended compares give the same result as sign-extended compares, if
+; the compare is unsigned. Just see: if both operands are <65536 they are the
+; same in both cases. If both are >=65536 the you effectively compare x+D
+; with y+D, where D=2**32-2**16, so the result is the same. if x<65536 and
+; y>=65536 then you compare x with y+D, and in both cases the result is x<y.
+
+(define_insn ""
+ [(set (cc0)
+ (compare (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m"))))]
+ "tahoe_cmp_check (insn, operands[0], 0)"
+ "cmpw %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (zero_extend:SI (match_operand:HI 0 "memory_operand" "m"))
+ (match_operand:SI 1 "immediate_operand" "i")))]
+ "tahoe_cmp_check(insn, operands[1], 65535)"
+ "*
+{
+ if (INTVAL (operands[1]) > 32767)
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) + 0xffff0000);
+ return \"cmpw %0,%1\";
+}")
+
+
+(define_insn ""
+ [(set (cc0)
+ (compare (sign_extend:SI (match_operand:QI 0 "memory_operand" "m"))
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
+ ""
+ "cmpb %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (match_operand:SI 0 "nonmemory_operand" "ri")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
+ ""
+ "cmpb %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (sign_extend:SI (match_operand:QI 0 "memory_operand" "m"))
+ (match_operand:SI 1 "nonmemory_operand" "ri")))]
+ ""
+ "cmpb %0,%1")
+
+; zero-extended compares give the same result as sign-extended compares, if
+; the compare is unsigned. Just see: if both operands are <128 they are the
+; same in both cases. If both are >=128 the you effectively compare x+D
+; with y+D, where D=2**32-2**8, so the result is the same. if x<128 and
+; y>=128 then you compare x with y+D, and in both cases the result is x<y.
+
+(define_insn ""
+ [(set (cc0)
+ (compare (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m"))))]
+ "tahoe_cmp_check (insn, operands[0], 0)"
+ "cmpb %0,%1")
+
+(define_insn ""
+ [(set (cc0)
+ (compare (zero_extend:SI (match_operand:QI 0 "memory_operand" "m"))
+ (match_operand:SI 1 "immediate_operand" "i")))]
+ "tahoe_cmp_check(insn, operands[1], 255)"
+ "*
+{
+ if (INTVAL (operands[1]) > 127)
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) + 0xffffff00);
+ return \"cmpb %0,%1\";
+}")
+
+
+(define_insn "cmpsi"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "nonimmediate_operand" "g")
+ (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "cmpl %0,%1")
+
+
+; cmpsf similar to vax, but first operand is expected to be in the
+; fpp accumulator.
+
+(define_insn "cmpsf"
+ [(set (cc0)
+ (compare (match_operand:SF 0 "general_operand" "a,g")
+ (match_operand:SF 1 "general_operand" "g,g")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0: return \"cmpf %1\";
+ case 1: return \"cmpf2 %0,%1\";
+ }
+}")
+
+
+; cmpdf similar to vax, but first operand is expected to be in the
+; fpp accumulator. Immediate doubles not allowed.
+
+(define_insn "cmpdf"
+ [(set (cc0)
+ (compare (match_operand:DF 0 "general_operand" "a,rm")
+ (match_operand:DF 1 "general_operand" "rm,rm")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0: return \"cmpd %1\";
+ case 1: return \"cmpd2 %0,%1\";
+ }
+}")
+
+;; 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" "g"))]
+ ""
+ "tstl %0")
+
+
+; small tests from memory are normal, but testing from registers doesn't
+; expand the data properly. So test in this case does a convert and tests
+; the new register data from the stack.
+
+; First some special cases that do work
+
+
+(define_insn ""
+ [(set (cc0)
+ (sign_extend:SI (match_operand:HI 0 "memory_operand" "m")))]
+ ""
+ "tstw %0")
+
+(define_insn ""
+ [(set (cc0)
+ (zero_extend:SI (match_operand:HI 0 "memory_operand" "m")))]
+ "tahoe_cmp_check (insn, operands[0], 0)"
+ "tstw %0")
+
+
+(define_insn "tsthi"
+ [(set (cc0)
+ (match_operand:HI 0 "extendable_operand" "m,!r"))]
+ "GET_MODE (operands[0]) != VOIDmode"
+ "*
+{
+ rtx xoperands[2];
+ extern rtx tahoe_reg_conversion_loc;
+ switch (which_alternative)
+ {
+ case 0:
+ return \"tstw %0\";
+ case 1:
+ xoperands[0] = operands[0];
+ xoperands[1] = tahoe_reg_conversion_loc;
+ output_asm_insn (\"movl %0,%1\", xoperands);
+ xoperands[1] = plus_constant (XEXP (tahoe_reg_conversion_loc, 0), 2);
+ output_asm_insn (\"tstw %a1\", xoperands);
+ return \"\";
+ }
+}")
+
+
+(define_insn ""
+ [(set (cc0)
+ (sign_extend:SI (match_operand:QI 0 "memory_operand" "m")))]
+ ""
+ "tstb %0")
+
+(define_insn ""
+ [(set (cc0)
+ (zero_extend:SI (match_operand:QI 0 "memory_operand" "m")))]
+ "tahoe_cmp_check (insn, operands[0], 0)"
+ "tstb %0")
+
+
+(define_insn "tstqi"
+ [(set (cc0)
+ (match_operand:QI 0 "extendable_operand" "m,!r"))]
+ "GET_MODE (operands[0]) != VOIDmode"
+ "*
+{
+ rtx xoperands[2];
+ extern rtx tahoe_reg_conversion_loc;
+ switch (which_alternative)
+ {
+ case 0:
+ return \"tstb %0\";
+ case 1:
+ xoperands[0] = operands[0];
+ xoperands[1] = tahoe_reg_conversion_loc;
+ output_asm_insn (\"movl %0,%1\", xoperands);
+ xoperands[1] = plus_constant (XEXP (tahoe_reg_conversion_loc, 0), 3);
+ output_asm_insn (\"tstb %a1\", xoperands);
+ return \"\";
+ }
+}")
+
+; tstsf compares a given value to a value already in the fpp accumulator.
+; No flags are set by this so ignore them.
+
+(define_insn "tstsf"
+ [(set (cc0)
+ (match_operand:SF 0 "register_operand" "a"))]
+ ""
+ "tstf")
+
+
+; tstdf compares a given value to a value already in the fpp accumulator.
+; immediate doubles not allowed. Flags are ignored after this.
+
+(define_insn "tstdf"
+ [(set (cc0)
+ (match_operand:DF 0 "register_operand" "a"))]
+ ""
+ "tstd")
+
+
+
+; movstrhi tahoe instruction does not load registers by itself like
+; the vax counterpart does. registers 0-2 must be primed by hand.
+; we have loaded the registers in the order: dst, src, count.
+
+(define_insn "movstrhi"
+ [(set (match_operand:BLK 0 "general_operand" "p")
+ (match_operand:BLK 1 "general_operand" "p"))
+ (use (match_operand:HI 2 "general_operand" "g"))
+ (clobber (reg:SI 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))]
+ ""
+ "movab %0,r1\;movab %1,r0\;movl %2,r2\;movblk")
+
+
+; floatsisf2 on tahoe converts the long from reg/mem into the fpp
+; accumulator. There are no hi and qi counterparts. Flags are not
+; set correctly here.
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (float:SF (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"cvlf %1\";
+}")
+
+
+; floatsidf2 on tahoe converts the long from reg/mem into the fpp
+; accumulator. There are no hi and qi counterparts. Flags are not
+; set correctly here.
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (float:DF (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"cvld %1\";
+}")
+
+
+; fix_truncsfsi2 to convert a float to long, tahoe must have the float
+; in the fpp accumulator. Flags are not set here.
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "a"))))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"cvfl %0\";
+}")
+
+
+; fix_truncsfsi2 to convert a double to long, tahoe must have the double
+; in the fpp accumulator. Flags are not set here.
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a"))))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"cvdl %0\";
+}")
+
+
+(define_insn "truncsihi2"
+ [(set (match_operand:HI 0 "general_operand" "=g")
+ (truncate:HI (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "cvtlw %1,%0")
+
+
+(define_insn "truncsiqi2"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (truncate:QI (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "cvtlb %1,%0")
+
+
+(define_insn "trunchiqi2"
+ [(set (match_operand:QI 0 "general_operand" "=g")
+ (truncate:QI (match_operand:HI 1 "general_operand" "g")))]
+ ""
+ "cvtwb %1,%0")
+
+
+; The fpp related instructions don't set flags, so ignore them
+; after this instruction.
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=a")
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "0")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"cvdf\";
+}")
+
+
+; This monster is to cover for the Tahoe's nasty habit of not extending
+; a number if the source is in a register. (It just moves it!) Case 0 is
+; a normal extend from memory. Case 1 does the extension from the top of
+; the stack. Extension from the stack doesn't set the flags right since
+; the moval changes them.
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "=g,?=g")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"cvtwl %1,%0\";
+ case 1:
+ if (push_operand (operands[0], SImode))
+ return \"pushl %1\;cvtwl 2(sp),(sp)\";
+ else
+ {
+ CC_STATUS_INIT;
+ return \"pushl %1\;cvtwl 2(sp),%0\;moval 4(sp),sp\";
+ }
+ }
+}")
+
+; This monster is to cover for the Tahoe's nasty habit of not extending
+; a number if the source is in a register. (It just moves it!) Case 0 is
+; a normal extend from memory. Case 1 does the extension from the top of
+; the stack. Extension from the stack doesn't set the flags right since
+; the moval changes them.
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "general_operand" "=g,?=g")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"cvtbl %1,%0\";
+ case 1:
+ if (push_operand (operands[0], SImode))
+ return \"pushl %1\;cvtbl 3(sp),(sp)\";
+ else
+ {
+ CC_STATUS_INIT;
+ return \"pushl %1\;cvtbl 3(sp),%0\;moval 4(sp),sp\";
+ }
+ }
+}")
+
+
+; This monster is to cover for the Tahoe's nasty habit of not extending
+; a number if the source is in a register. (It just moves it!) Case 0 is
+; a normal extend from memory. Case 1 does the extension from the top of
+; the stack. Extension from the stack doesn't set the flags right since
+; the moval changes them.
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "general_operand" "=g,?=g")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"cvtbw %1,%0\";
+ case 1:
+ if (push_operand (operands[0], SImode))
+ return \"pushl %1\;cvtbw 3(sp),(sp)\";
+ else
+ {
+ CC_STATUS_INIT;
+ return \"pushl %1\;cvtbw 3(sp),%0\;moval 4(sp),sp\";
+ }
+ }
+}")
+
+
+; extendsfdf2 tahoe uses the fpp accumulator to do the extension.
+; It takes a float and loads it up directly as a double.
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=a")
+ (float_extend:DF (match_operand:SF 1 "general_operand" "g")))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ return \"ldfd %1\";
+}")
+
+
+; movz works fine from memory but not from register for the same reasons
+; the cvt instructions don't work right. So we use the normal instruction
+; from memory and we use an and to simulate it from register. This is faster
+; than pulling it off the stack.
+
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "general_operand" "=g,?=g")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0: return \"movzwl %1,%0\";
+ case 1: return \"andl3 $0xffff,%1,%0\";
+ }
+}")
+
+; movz works fine from memory but not from register for the same reasons
+; the cvt instructions don't work right. So we use the normal instruction
+; from memory and we use an and to simulate it from register. This is faster
+; than pulling it off the stack.
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "general_operand" "=g,?=g")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0: return \"movzbw %1,%0\";
+ case 1: return \"andw3 $0xff,%1,%0\";
+ }
+}")
+
+
+; movz works fine from memory but not from register for the same reasons
+; the cvt instructions don't work right. So we use the normal instruction
+; from memory and we use an and to simulate it from register. This is faster
+; than pulling it off the stack.
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "general_operand" "=g,?=g")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
+ ""
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0: return \"movzbl %1,%0\";
+ case 1: return \"andl3 $0xff,%1,%0\";
+ }
+}")
+
+
+(define_insn "beq"
+ [(set (pc)
+ (if_then_else (eq (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jeql %l0")
+
+
+(define_insn "bne"
+ [(set (pc)
+ (if_then_else (ne (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jneq %l0")
+
+
+(define_insn "bgt"
+ [(set (pc)
+ (if_then_else (gt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jgtr %l0")
+
+
+(define_insn "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jgtru %l0")
+
+
+(define_insn "blt"
+ [(set (pc)
+ (if_then_else (lt (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jlss %l0")
+
+
+(define_insn "bltu"
+ [(set (pc)
+ (if_then_else (ltu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jlssu %l0")
+
+
+(define_insn "bge"
+ [(set (pc)
+ (if_then_else (ge (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jgeq %l0")
+
+
+(define_insn "bgeu"
+ [(set (pc)
+ (if_then_else (geu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jgequ %l0")
+
+
+(define_insn "ble"
+ [(set (pc)
+ (if_then_else (le (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jleq %l0")
+
+
+(define_insn "bleu"
+ [(set (pc)
+ (if_then_else (leu (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "jlequ %l0")
+
+
+; gcc does not account for register mask/argc longword. Thus the number
+; for the call = number bytes for args + 4
+
+(define_insn "call"
+ [(call (match_operand:QI 0 "memory_operand" "m")
+ (match_operand:QI 1 "general_operand" "g"))]
+ ""
+ "*
+{
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[1]) + 4));
+ if (GET_CODE(operands[0]) == MEM
+ && CONSTANT_ADDRESS_P (XEXP(operands[0], 0))
+ && INTVAL (operands[1]) < 64)
+ return \"callf %1,%0\"; /* this is much faster */
+ return \"calls %1,%0\";
+}")
+
+; gcc does not account for register mask/argc longword. Thus the number
+; for the call = number bytes for args + 4
+
+(define_insn "call_value"
+ [(set (match_operand 0 "" "=g")
+ (call (match_operand:QI 1 "memory_operand" "m")
+ (match_operand:QI 2 "general_operand" "g")))]
+ ""
+ "*
+{
+ operands[2] = gen_rtx (CONST_INT, VOIDmode, (INTVAL (operands[2]) + 4));
+ if (GET_CODE(operands[1]) == MEM
+ && CONSTANT_ADDRESS_P (XEXP(operands[1], 0))
+ && INTVAL (operands[2]) < 64)
+ return \"callf %2,%1\"; /* this is much faster */
+ return \"calls %2,%1\";
+}")
+
+
+(define_insn "return"
+ [(return)]
+ ""
+ "ret")
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+
+; casesi this code extracted from the vax code. The instructions are
+; very similar. Tahoe requires that the table be word aligned. GCC
+; places the table immediately after, thus the alignment directive.
+
+(define_insn "casesi"
+ [(set (pc)
+ (if_then_else (le (minus:SI (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g"))
+ (match_operand:SI 2 "general_operand" "g"))
+ (plus:SI (sign_extend:SI
+ (mem:HI (plus:SI (pc)
+ (minus:SI (match_dup 0)
+ (match_dup 1)))))
+ (label_ref:SI (match_operand 3 "" "")))
+ (pc)))]
+ ""
+ "casel %0,%1,%2\;.align %@")
+
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "jbr %l0")
+
+
+;; This is the list of all the non-standard insn patterns
+
+
+; This is used to access the address of a byte. This is similar to
+; movqi, but the second operand had to be "address_operand" type, so
+; it had to be an unnamed one.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (match_operand:QI 1 "address_operand" "p"))]
+ ""
+ "*
+{
+ if (push_operand (operands[0], SImode))
+ return \"pushab %a1\";
+ return \"movab %a1,%0\";
+}")
+
+; This is used to access the address of a word. This is similar to
+; movhi, but the second operand had to be "address_operand" type, so
+; it had to be an unnamed one.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (match_operand:HI 1 "address_operand" "p"))]
+ ""
+ "*
+{
+ if (push_operand (operands[0], SImode))
+ return \"pushaw %a1\";
+ return \"movaw %a1,%0\";
+}")
+
+; This is used to access the address of a long. This is similar to
+; movsi, but the second operand had to be "address_operand" type, so
+; it had to be an unnamed one.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "general_operand" "=g")
+ (match_operand:SI 1 "address_operand" "p"))]
+ ""
+ "*
+{
+ if (push_operand (operands[0], SImode))
+ return \"pushal %a1\";
+ return \"moval %a1,%0\";
+}")
+
+
+; bit test longword instruction, same as vax
+
+(define_insn ""
+ [(set (cc0)
+ (and:SI (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g")))]
+ ""
+ "bitl %0,%1")
+
+
+; bit test word instructions, same as vax
+
+(define_insn ""
+ [(set (cc0)
+ (and:HI (match_operand:HI 0 "general_operand" "g")
+ (match_operand:HI 1 "general_operand" "g")))]
+ ""
+ "bitw %0,%1")
+
+
+; bit test instructions, same as vax
+
+(define_insn ""
+ [(set (cc0)
+ (and:QI (match_operand:QI 0 "general_operand" "g")
+ (match_operand:QI 1 "general_operand" "g")))]
+ ""
+ "bitb %0,%1")
+
+
+; bne counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jneq %l0")
+
+
+; beq counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jeql %l0")
+
+
+; ble counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (gt (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jleq %l0")
+
+
+; bleu counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (gtu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jlequ %l0")
+
+
+; bge counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (lt (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jgeq %l0")
+
+
+; bgeu counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ltu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jgequ %l0")
+
+
+; blt counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ge (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jlss %l0")
+
+
+; bltu counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (geu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jlssu %l0")
+
+
+; bgt counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (le (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jgtr %l0")
+
+
+; bgtu counterpart. in case gcc reverses the conditional.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (leu (cc0)
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "jgtru %l0")
+
+
+; casesi alternate form as found in vax code. this form is to
+; compensate for the table's offset being no distance (0 displacement)
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (le (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g"))
+ (plus:SI (sign_extend:SI
+ (mem:HI (plus:SI (pc)
+ (minus:SI (match_dup 0)
+ (const_int 0)))))
+ (label_ref:SI (match_operand 3 "" "")))
+ (pc)))]
+ ""
+ "casel %0,$0,%1\;.align %@")
+
+
+; casesi alternate form as found in vax code. another form to
+; compensate for the table's offset being no distance (0 displacement)
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (le (match_operand:SI 0 "general_operand" "g")
+ (match_operand:SI 1 "general_operand" "g"))
+ (plus:SI (sign_extend:SI
+ (mem:HI (plus:SI (pc)
+ (match_dup 0))))
+ (label_ref:SI (match_operand 3 "" "")))
+ (pc)))]
+ ""
+ "casel %0,$0,%1 \;.align %@")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (lt (plus:SI (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (match_operand:SI 1 "general_operand" "g"))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "aoblss %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (le (plus:SI (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (match_operand:SI 1 "general_operand" "g"))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "aobleq %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ge (plus:SI (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (match_operand:SI 1 "general_operand" "g"))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "aoblss %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (gt (plus:SI (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (match_operand:SI 1 "general_operand" "g"))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "aobleq %1,%0,%l2")
+
+; bbs/bbc
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "bbs %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "bbc %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "bbc %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (subreg:QI (match_operand:SI 1 "general_operand" "g") 0))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "bbs %1,%0,%l2")
+
+; if the shift count is a byte in a register we can use it as a long
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand:QI 1 "register_operand" "r"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "bbs %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand:QI 1 "register_operand" "r"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "bbc %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand:QI 1 "register_operand" "r"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "bbc %1,%0,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (sign_extract:SI (match_operand:SI 0 "nonimmediate_operand" "rm")
+ (const_int 1)
+ (match_operand:QI 1 "register_operand" "r"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "bbs %1,%0,%l2")
+
+; special case for 1 << constant. We don't do these because they are slower
+; than the bitl instruction
+
+;(define_insn ""
+; [(set (pc)
+; (if_then_else
+; (ne (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
+; (match_operand:SI 1 "immediate_operand" "i"))
+; (const_int 0))
+; (label_ref (match_operand 2 "" ""))
+; (pc)))]
+; "GET_CODE (operands[1]) == CONST_INT
+; && exact_log2 (INTVAL (operands[1])) >= 0"
+; "*
+;{
+; operands[1]
+; = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1])));
+; return \"bbs %1,%0,%l2\";
+;}")
+;
+;(define_insn ""
+; [(set (pc)
+; (if_then_else
+; (eq (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
+; (match_operand:SI 1 "immediate_operand" "i"))
+; (const_int 0))
+; (label_ref (match_operand 2 "" ""))
+; (pc)))]
+; "GET_CODE (operands[1]) == CONST_INT
+; && exact_log2 (INTVAL (operands[1])) >= 0"
+; "*
+;{
+; operands[1]
+; = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1])));
+; return \"bbc %1,%0,%l2\";
+;}")
+;
+;(define_insn ""
+; [(set (pc)
+; (if_then_else
+; (ne (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
+; (match_operand:SI 1 "immediate_operand" "i"))
+; (const_int 0))
+; (pc)
+; (label_ref (match_operand 2 "" ""))))]
+; "GET_CODE (operands[1]) == CONST_INT
+; && exact_log2 (INTVAL (operands[1])) >= 0"
+; "*
+;{
+; operands[1]
+; = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1])));
+; return \"bbc %1,%0,%l2\";
+;}")
+;
+;(define_insn ""
+; [(set (pc)
+; (if_then_else
+; (eq (and:SI (match_operand:SI 0 "nonimmediate_operand" "%rm")
+; (match_operand:SI 1 "immediate_operand" "i"))
+; (const_int 0))
+; (pc)
+; (label_ref (match_operand 2 "" ""))))]
+; "GET_CODE (operands[1]) == CONST_INT
+; && exact_log2 (INTVAL (operands[1])) >= 0"
+; "*
+;{
+; operands[1]
+; = gen_rtx (CONST_INT, VOIDmode, exact_log2 (INTVAL (operands[1])));
+; return \"bbs %1,%0,%l2\";
+;}")
diff --git a/gnu/usr.bin/gcc/config/tahoe/xm-tahoe.h b/gnu/usr.bin/gcc/config/tahoe/xm-tahoe.h
new file mode 100644
index 00000000000..1af7bdda31e
--- /dev/null
+++ b/gnu/usr.bin/gcc/config/tahoe/xm-tahoe.h
@@ -0,0 +1,59 @@
+/* Configuration for GNU C-compiler for Tahoe.
+ 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. */
+
+/*
+ * File: xm-tahoe.h
+ *
+ * Original port made at the University of Buffalo by Devon Bowen,
+ * Dale Wiles and Kevin Zachmann.
+ *
+ * Changes for HCX by Piet van Oostrum,
+ * University of Utrecht, The Netherlands (piet@cs.ruu.nl)
+ *
+ * Mail bugs reports or fixes to: gcc@cs.buffalo.edu
+ */
+
+
+/* This file has the same stuff the vax version does */
+
+/* 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
+
+#define HOST_WORDS_BIG_ENDIAN
+
+/* Arguments to use with `exit'. */
+
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33