diff options
author | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-06 01:47:28 -0800 |
commit | be8b04496302184c6e8f04d6179f9c3afc50aeb6 (patch) | |
tree | 726e2468c0c07add773c0dbd86ab6386844259ae /gcc/config/m68k |
initial commit
Diffstat (limited to 'gcc/config/m68k')
129 files changed, 31223 insertions, 0 deletions
diff --git a/gcc/config/m68k/3b1.h b/gcc/config/m68k/3b1.h new file mode 100755 index 0000000..2b6611a --- /dev/null +++ b/gcc/config/m68k/3b1.h @@ -0,0 +1,513 @@ +/* Definitions of target machine for GNU compiler. + AT&T UNIX PC version (pc7300, 3b1) + Copyright (C) 1987, 1993, 1996 Free Software Foundation, Inc. + Contributed by Alex Crain (alex@umbc3.umd.edu). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define SGS_SWITCH_TABLES /* Different switch table handling */ + +#include "m68k/hp320.h" + +/* See m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0 + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* -m68020 requires special flags to the assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "%{m68020:-68020}%{!m68020:-68010} %{m68881:-68881}" + +/* we use /lib/libp/lib* when profiling */ + +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{p:-L/lib/libp} %{pg:-L/lib/libp} -lc}" + +/* shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} " + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ +output_file_directive ((FILE), main_input_filename) + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68k -Dunix -Dunixpc -D__motorola__ -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7"} + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (((MODE) == BLKmode \ + ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ + && int_size_in_bytes (TYPE) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY) \ + ? downward : none) + +/* The 3b1 does not have `atexit'. */ + +#undef HAVE_ATEXIT + +/* Override parts of m68k.h to fit the SGS-3b1 assembler. */ + +#undef TARGET_VERSION +#undef ASM_FORMAT_PRIVATE_NAME +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SOURCE_FILENAME +#undef ASM_OUTPUT_SOURCE_LINE +#undef PRINT_OPERAND_ADDRESS +#undef ASM_GENERATE_INTERNAL_LABEL +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_OPCODE +#undef ASM_OUTPUT_LOCAL +#undef USER_LABEL_PREFIX +#undef ASM_OUTPUT_ASCII + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T unixpc syntax)"); + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +/* The unixpc doesn't know about double's and float's */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tlong 0x%x,0x%x\n", l[0], l[1]); \ + } while (0) + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tlong 0x%x,0x%x,0x%x\n", l[0], l[1], l[2]); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "\tlong 0x%x\n", l); \ + } while (0) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %d\n", (SIZE)) + +/* Can't use ASM_OUTPUT_SKIP in text section; it doesn't leave 0s. */ + +#define ASM_NO_SKIP_IN_TEXT 1 + +/* The beginnings of sdb support... */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + do { fprintf (FILE, "\tfile\t"); \ + output_quoted_string (FILE, FILENAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + do { register int sp = 0, lp = 0; \ + fprintf ((FILE), "\tbyte\t"); \ + loop: \ + if ((PTR)[sp] > ' ' && ! ((PTR)[sp] & 0x80) && (PTR)[sp] != '\\') \ + { lp += 3; \ + fprintf ((FILE), "'%c", (PTR)[sp]); } \ + else \ + { lp += 5; \ + fprintf ((FILE), "0x%x", (PTR)[sp]); } \ + if (++sp < (LEN)) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf ((FILE), "\n\t%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', (FILE)); \ + goto loop; } \ + putc ('\n', (FILE)); } while (0) + +/* Note that in the case of the movhi which fetches an element of + an ADDR_DIFF_VEC the offset output is too large by 2. + This is because the 3b1 assembler refuses to subtract 2. + ASM_OUTPUT_CASE_LABEL, below, compensates for this. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "LD%%%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + fprintf (FILE, ")"); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "LD%%%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%%%d:\n", PREFIX, NUM) + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +/* ihnp4!lmayk!lgm says that `short 0' triggers assembler bug; + `short L%nn-L%nn' supposedly works. */ +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + if (! RTX_INTEGRATED_P (TABLE)) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + else \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n\tshort %s%%%d-%s%%%d\n", \ + XVECLEN (PATTERN (TABLE), 1) + 1, (PREFIX), (NUM), \ + (PREFIX), (NUM), (PREFIX), (NUM)) + +/* At end of a switch table, define LDnnn iff the symbol LInnn was defined. + Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" + fails to assemble. Luckily "LDnnn(pc,d0.l*2)" produces the results + we want. This difference can be accommodated by making the assembler + define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other + string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END + macro. */ + +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +{ if (switch_table_difference_label_flag) \ + fprintf (FILE, "\tset LD%%%d,L%%%d-LI%%%d\n", (NUM), (NUM), (NUM)); \ + switch_table_difference_label_flag = 0; } + +int switch_table_difference_label_flag; + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 's') \ + { \ + if (!strncmp ((PTR), "swap", 4)) \ + { fprintf ((FILE), "swap.w"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbneq"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' \ + || (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'm') (PTR)++; } \ +} + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#define USER_LABEL_PREFIX "" + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +/* Define subroutines to call to handle multiply, divide, and remainder. + Use the subroutines that the 3b1's library provides. + The `*' prevents an underscore from being prepended by the compiler. */ + +#define DIVSI3_LIBCALL "*ldiv" +#define UDIVSI3_LIBCALL "*uldiv" +#define MODSI3_LIBCALL "*lrem" +#define UMODSI3_LIBCALL "*ulrem" +#define MULSI3_LIBCALL "*lmul" +#define UMULSI3_LIBCALL "*ulmul" + +/* Definitions for collect2. */ + +#define OBJECT_FORMAT_COFF +#define NO_SYS_SIGLIST +#define MY_ISCOFF(magic) \ + ((magic) == MC68KWRMAGIC || (magic) == MC68KROMAGIC || (magic) == MC68KPGMAGIC) diff --git a/gcc/config/m68k/3b1g.h b/gcc/config/m68k/3b1g.h new file mode 100755 index 0000000..2b1d23c --- /dev/null +++ b/gcc/config/m68k/3b1g.h @@ -0,0 +1,64 @@ +/* Definitions of target machine for GNU compiler, for a 3b1 using GAS. + Copyright (C) 1987, 1988 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 "m68k/m68k.h" + +/* See m68k.h. 0 means 68000 with no 68881. */ +#define TARGET_DEFAULT 0 + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ +#define CPP_PREDEFINES "-Dmc68000 -Dmc68k -Dunix -Dunixpc -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" + +/* This is (not really) BSD, so (but) it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Brain damage. */ +#define SCCS_DIRECTIVE + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (((MODE) == BLKmode \ + ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ + && int_size_in_bytes (TYPE) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY) \ + ? downward : none) + +/* Every structure or union's size must be a multiple of 2 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + diff --git a/gcc/config/m68k/a-ux.h b/gcc/config/m68k/a-ux.h new file mode 100755 index 0000000..69ecb53 --- /dev/null +++ b/gcc/config/m68k/a-ux.h @@ -0,0 +1,206 @@ +/* Definitions for Motorola 680x0 running A/UX + Copyright (C) 1996, 1998 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. */ + +/* This file was renamed from aux.h because of MSDOS: aux.anything + isn't usable. Sigh. */ + +/* Execution environment */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) /* 68020, 68881 */ + +#define CPP_PREDEFINES "-Dunix -Dm68k -DAUX -DmacII \ +-Asystem(unix) -Asystem(AUX) -Acpu(m68k) -Amachine(m68k) -Amachine(macII)" + +#define CPP_SPEC \ +"%{!msoft-float:%{!ansi:-Dmc68881 }-D__HAVE_68881__ }\ +-Acpu(mc68000) -D__mc68000__ %{!ansi:-Dmc68000 }\ +%{!mc68000:%{!m68000:-Acpu(mc68020) -D__mc68020__ %{!ansi:-Dmc68020 }}}\ +%{m68030:-Acpu(mc68030) -D__mc68030__ %{!ansi:-Dmc68030 }}\ +%{m68040:-Acpu(mc68040) -D__mc68040__ %{!ansi:-Dmc68040 }}\ +%{!ansi:%{!traditional:-D__STDC__=2 }}\ +%{sbsd:-D_BSD_SOURCE -DBSD }%{ZB:-D_BSD_SOURCE -DBSD }\ +%{ssysv:-D_SYSV_SOURCE -DSYSV -DUSG }%{ZS:-D_SYSV_SOURCE -DSYSV -DUSG }\ +%{sposix:-D_POSIX_SOURCE -DPOSIX }%{ZP:-D_POSIX_SOURCE -DPOSIX }\ +%{sposix+:-D_POSIX_SOURCE -DPOSIX }\ +%{saux:-D_AUX_SOURCE }%{ZA:-D_AUX_SOURCE }\ +%{!sbsd:%{!ZB:%{!ssysv:%{!ZS:%{!sposix:%{!ZP:%{!snone:\ +-D_BSD_SOURCE -D_SYSV_SOURCE -D_AUX_SOURCE }}}}}}}" + +#define LIB_SPEC \ +"%{sbsd:-lbsd }%{ZB:-lbsd }\ +%{ssysv:-lsvid }%{ZS:-lsvid }\ +%{sposix:-lposix }%{ZP:-lposix }%{sposix+:-lposix }\ +%{!static:%{smac:-lmac_s -lat -lld -lmr }-lc_s }\ +%{static:%{smac:-lmac -lat -lld -lmr }-lc }" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"%{pg:mcrt0.o%s }%{!pg:%{p:mcrt1.o%s }\ +%{!p:%{smac:maccrt1.o%s low.o%s }%{!smac:crt1.o%s }}}\ +crt2.o%s " + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtn.o%s " + + +/*===================================================================*/ +/* Compilation environment -- mostly */ + +#define NO_SYS_SIGLIST + +/* We provide atexit(), A/UX does not have it */ +#define HAVE_ATEXIT + +/* Generate calls to memcpy, memcmp and memset, as opposed to bcopy, bcmp, + and bzero */ +#define TARGET_MEM_FUNCTIONS + +/* Resize standard types */ + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "unsigned int" + +/* Every structure or union's size must be a multiple of 2 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Bits needed by collect */ + +#define OBJECT_FORMAT_COFF +#define MY_ISCOFF(m) ((m) == M68TVMAGIC || \ + (m) == M68MAGIC || \ + (m) == MC68TVMAGIC || \ + (m) == MC68MAGIC || \ + (m) == M68NSMAGIC) + + +#ifndef USE_COLLECT2 +/* For .ctor/.dtor sections for collecting constructors */ +/* We have special start/end files for defining [cd]tor lists */ +#define CTOR_LISTS_DEFINED_EXTERNALLY +#endif + + +/*======================================================================*/ +/* Calling convention and library support changes */ + +/* Define how to generate (in the callee) the output value of a function + and how to find (in the caller) the value returned by a function. VALTYPE + is the data type of the value (as a tree). If the precise function being + called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. + For A/UX generate the result in d0, a0, or fp0 as appropriate. */ + +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_68881 \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : (POINTER_TYPE_P (VALTYPE) \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0))) + +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && \ + ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +/* 1 if N is a possible register number for a function value. + For A/UX allow d0, a0, or fp0 as return registers, for integral, + pointer, or floating types, respectively. Reject fp0 if not using a + 68881 coprocessor. */ + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (N) == 8 || (TARGET_68881 && (N) == 16)) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 + +/* For compatibility with the large body of existing code which does not + always properly declare external functions returning pointer types, the + A/UX convention is to copy the value returned for pointer functions + from a0 to d0 in the function epilogue, so that callers that have + neglected to properly declare the callee can still find the correct return + value. */ + +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +{ \ + extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\t%s %Ra0,%Rd0\n", ASM_MOV_INSN); \ +} + +/* How to call the function profiler */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + asm_fprintf (FILE, "\t%Olea %LLP%d,%Ra0\n\t%Ojbsr %s\n", \ + (LABELNO), FUNCTION_PROFILER_SYMBOL) + +/* Finalize the trampoline by flushing the insn cache */ + +#undef FINALIZE_TRAMPOLINE +#define FINALIZE_TRAMPOLINE(TRAMP) \ + emit_library_call(gen_rtx(SYMBOL_REF, Pmode, "__clear_cache"), \ + 0, VOIDmode, 2, TRAMP, Pmode, \ + plus_constant(TRAMP, TRAMPOLINE_SIZE), Pmode); + +/* Clear the instruction cache from `beg' to `end'. This makes an + inline system call to SYS_sysm68k. The arguments are as follows: + + sysm68k(105, addr, scope, cache, len) + + 105 - the subfunction code to clear the cache + addr - the start address for the flush + scope - the scope of the flush (see the cpush insn) + cache - which cache to flush (see the cpush insn) + len - a factor relating to the number of flushes to perform : + len/16 lines, or len/4096 pages. + + While all this is only really relevant to 040's, the system call + will just return an error (which we ignore) on other systems. */ + +#define CLEAR_INSN_CACHE(beg, end) \ +{ \ + unsigned _beg = (unsigned)(beg), _end = (unsigned)(end); \ + unsigned _len = ((_end / 16) - (_beg / 16) + 1) * 16; \ + __asm __volatile( \ + ASM_MOV_INSN " %1, %-\n\t" /* nr lines */ \ + ASM_MOV_INSN " %#3, %-\n\t" /* insn+data caches */ \ + ASM_MOV_INSN " %#1, %-\n\t" /* clear lines */ \ + ASM_MOV_INSN " %0, %-\n\t" /* beginning of buffer */ \ + ASM_MOV_INSN " %#105, %-\n\t" /* cache sub-function nr */ \ + ASM_MOV_INSN " %#0, %-\n\t" /* dummy return address */ \ + ASM_MOV_INSN " %#38, %/d0\n\t" /* system call nr */ \ + "trap %#0\n\t" \ + "add%.l %#24, %/sp" \ + : /* no outputs */ \ + : "g"(_beg), "g"(_len) \ + : "%d0"); \ +} diff --git a/gcc/config/m68k/altos3068.h b/gcc/config/m68k/altos3068.h new file mode 100755 index 0000000..5903a12 --- /dev/null +++ b/gcc/config/m68k/altos3068.h @@ -0,0 +1,135 @@ +/* Definitions of target machine for GNU compiler. Altos 3068 68020 version. + Copyright (C) 1988, 1989, 1993, 1996 Free Software Foundation, Inc. + Contributed by Jyrki Kuoppala <jkp@cs.hut.fi> + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ +/* 5 is without 68881. Change to 7 if you have 68881 */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 +#endif + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & MASK_68881 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -DPORTAR -Dmc68k32 -Uvax -Dm68k -Dunix -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* We use gnu assembler, linker and gdb, so we want DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Tell some conditionals we will use GAS. Is this really used? */ + +#define USE_GAS + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", dstr); \ + fprintf (FILE, "\t.single 0r%s\n", dstr); \ + } while (0) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE == 'f') \ + { \ + char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + else \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I0x%x", l); \ + else \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } while (0) + +/* Return pointer values in both d0 and a0. */ + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +{ \ + extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode))\ + fprintf (FILE, "\tmovel d0,a0\n"); \ +} diff --git a/gcc/config/m68k/amix.h b/gcc/config/m68k/amix.h new file mode 100755 index 0000000..9b40a29 --- /dev/null +++ b/gcc/config/m68k/amix.h @@ -0,0 +1,149 @@ +/* Definitions of target machine for GNU compiler. + Commodore Amiga A3000UX version. + + Copyright (C) 1991, 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 1, 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 "m68k/m68kv4.h" + +/* rhealey@aggregate.com says dots are no good either. */ +#define NO_DOT_IN_LABEL + +/* Alter assembler syntax for fsgldiv and fsglmul. + It is highly likely that this is a generic SGS m68k assembler dependency. + If so, it should eventually be handled in the m68k/sgs.h ASM_OUTPUT_OPCODE + macro, like the other SGS assembler quirks. -fnf */ + +#define FSGLDIV_USE_S /* Use fsgldiv.s, not fsgldiv.x */ +#define FSGLMUL_USE_S /* Use fsglmul.s, not fsglmul.x */ + +/* Names to predefine in the preprocessor for this target machine. For the + Amiga, these definitions match those of the native AT&T compiler. Note + that we override the definition in m68kv4.h, where SVR4 is defined and + AMIX isn't. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Dm68k -Dunix -DAMIX -D__svr4__ -D__motorola__ \ + -Amachine(m68k) -Acpu(m68k) -Asystem(unix) -Alint(off)" + +/* At end of a switch table, define LDnnn iff the symbol LInnn was defined. + Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" + fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results + we want. This difference can be accommodated by making the assembler + define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other + string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END + macro. (the Amiga assembler has this bug) */ + +#undef ASM_OUTPUT_CASE_END +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +do { \ + if (switch_table_difference_label_flag) \ + asm_fprintf ((FILE), "\t%s %LLD%d,%LL%d\n", SET_ASM_OP, (NUM), (NUM));\ + switch_table_difference_label_flag = 0; \ +} while (0) + +int switch_table_difference_label_flag; + +/* This says how to output assembler code to declare an + uninitialized external linkage data object. Under SVR4, + the linker seems to want the alignment of data objects + to depend on their types. We do exactly that here. + [This macro overrides the one in svr4.h because the amix assembler + has a minimum default alignment of 4, and will not accept any + explicit alignment smaller than this. -fnf] */ + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ +do { \ + fputs ("\t.comm\t", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%u,%u\n", (SIZE), MAX ((ALIGN) / BITS_PER_UNIT, 4)); \ +} while (0) + +/* This says how to output assembler code to declare an + uninitialized internal linkage data object. Under SVR4, + the linker seems to want the alignment of data objects + to depend on their types. We do exactly that here. + [This macro overrides the one in svr4.h because the amix assembler + has a minimum default alignment of 4, and will not accept any + explicit alignment smaller than this. -fnf] */ + +#undef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ +do { \ + fprintf ((FILE), "\t%s\t%s,%u,%u\n", \ + BSS_ASM_OP, (NAME), (SIZE), MAX ((ALIGN) / BITS_PER_UNIT, 4)); \ +} while (0) + +/* This definition of ASM_OUTPUT_ASCII is the same as the one in m68k/sgs.h, + which has been overridden by the one in svr4.h. However, we can't use + the one in svr4.h because the amix assembler croaks on some of the + strings that it emits (such as .string "\"%s\"\n"). */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +do { \ + register int sp = 0, lp = 0, ch; \ + fprintf ((FILE), "\t%s ", BYTE_ASM_OP); \ + do { \ + ch = (PTR)[sp]; \ + if (ch > ' ' && ! (ch & 0x80) && ch != '\\') \ + { \ + fprintf ((FILE), "'%c", ch); \ + } \ + else \ + { \ + fprintf ((FILE), "0x%x", ch); \ + } \ + if (++sp < (LEN)) \ + { \ + if ((sp % 10) == 0) \ + { \ + fprintf ((FILE), "\n\t%s ", BYTE_ASM_OP); \ + } \ + else \ + { \ + putc (',', (FILE)); \ + } \ + } \ + } while (sp < (LEN)); \ + putc ('\n', (FILE)); \ +} while (0) + +/* The following should be unnecessary as a result of PIC_CASE_VECTOR_ADDRESS. + But rhealey@aggregate.com says they are still needed. */ + +/* Override these for the sake of an assembler bug: the Amix + assembler can't handle .LC0@GOT syntax. This pollutes the final + table for shared librarys but what's a poor soul to do; sigh... RFH */ + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + if (flag_pic && !strcmp(PREFIX,"LC")) \ + sprintf (LABEL, "*%s%%%d", PREFIX, NUM); \ + else \ + sprintf (LABEL, "*%s%s%d", LOCAL_LABEL_PREFIX, PREFIX, NUM) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + if (flag_pic && !strcmp(PREFIX,"LC")) \ + asm_fprintf (FILE, "%s%%%d:\n", PREFIX, NUM); \ + else \ + asm_fprintf (FILE, "%0L%s%d:\n", PREFIX, NUM) diff --git a/gcc/config/m68k/apollo68.h b/gcc/config/m68k/apollo68.h new file mode 100755 index 0000000..8eed141 --- /dev/null +++ b/gcc/config/m68k/apollo68.h @@ -0,0 +1,208 @@ +/* Definitions of target machine for GNU compiler. Apollo 680X0 version. + Copyright (C) 1989, 1992, 1996, 1997 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 "m68k/m68k.h" + +/* This symbol may be tested in other files for special Apollo handling */ + +#define TM_APOLLO + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* Target switches for the Apollo is the same as in m68k.h, except + there is no Sun FPA. */ + +#undef TARGET_SWITCHES +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "", TARGET_DEFAULT}} + +/* Define __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & MASK_68881 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68000:-Dmc68010 }%{mc68000:-Dmc68010 }%{!mc68000:%{!m68000:-Dmc68020 }}\ +%{!ansi:-D_APOLLO_SOURCE}}" + +#endif + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Apollo, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dapollo -Daegis -Dunix -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Allow #ident but output nothing for it. */ + +#define IDENT_DIRECTIVE +#define ASM_OUTPUT_IDENT(FILE, NAME) + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}}" + +/* STARTFILE_SPEC + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 */ + +#if TARGET_DEFAULT & MASK_68881 +/* -m68881 is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" +#else +/* -msoft-float is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" +#endif + +/* Specify library to handle `-a' basic block profiling. */ + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o} " + +/* Debugging is not supported yet */ + +#undef DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +/* We have atexit(2). So C++ can use it for global destructors. */ + +#if 0 /* troy@cbme.unsw.edu.au says people are still using sr10.2 + and it does not support atexit. */ +#define HAVE_ATEXIT +#endif + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Functions which return large structures get the address + to place the wanted value from a hidden parameter. */ + +#undef PCC_STATIC_STRUCT_RETURN +#undef STRUCT_VALUE_REGNUM +#define STRUCT_VALUE 0 +#define STRUCT_VALUE_INCOMING 0 + +/* Specify how to pad function arguments. + Arguments are not padded at all; the stack is kept aligned on long + boundaries. */ + +#define FUNCTION_ARG_PADDING(mode, size) none + +/* The definition of this macro imposes a limit on the size of + an aggregate object which can be treated as if it were a scalar + object. */ + +#define MAX_FIXED_MODE_SIZE BITS_PER_WORD + +/* The definition of this macro implies that there are cases where + a scalar value cannot be returned in registers. + For Apollo, anything larger than one integer register is returned + using the structure-value mechanism, i.e. objects of DFmode are + returned that way. */ + +#define RETURN_IN_MEMORY(type) \ + (TYPE_MODE (type) == BLKmode \ + || GET_MODE_SIZE (TYPE_MODE (type)) > UNITS_PER_WORD) + +/* In order to link with Apollo libraries, we can't prefix external + symbols with an underscore. */ + +#undef USER_LABEL_PREFIX + +/* Use a prefix for local labels, just to be on the save side. */ + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* Use a register prefix to avoid clashes with external symbols (classic + example: `extern char PC;' in termcap). */ + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +/* config/m68k.md has an explicit reference to the program counter, + prefix this by the register prefix. */ + +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp %%pc@(2,%0:l)"; \ + else \ + return "jmp %%pc@(2,%0:w)" \ + } while (0) + +/* Here are the new register names. */ + +#undef REGISTER_NAMES +#ifndef SUPPORT_SUN_FPA +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7" } +#else /* SUPPORTED_SUN_FPA */ +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6", "%fpa7", \ + "%fpa8", "%fpa9", "%fpa10", "%fpa11", "%fpa12", "%fpa13", "%fpa14", "%fpa15", \ + "%fpa16", "%fpa17", "%fpa18", "%fpa19", "%fpa20", "%fpa21", "%fpa22", "%fpa23", \ + "%fpa24", "%fpa25", "%fpa26", "%fpa27", "%fpa28", "%fpa29", "%fpa30", "%fpa31" } +#endif /* defined SUPPORT_SUN_FPA */ diff --git a/gcc/config/m68k/atari.h b/gcc/config/m68k/atari.h new file mode 100755 index 0000000..da0a803 --- /dev/null +++ b/gcc/config/m68k/atari.h @@ -0,0 +1,106 @@ +/* Definitions of target machine for GNU compiler. + Atari TT ASV version. + Copyright (C) 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 1, 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 "m68k/m68kv4.h" + +/* Dollars and dots in labels are not allowed. */ + +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL + +/* Alter assembler syntax for fsgldiv and fsglmul. + It is highly likely that this is a generic SGS m68k assembler dependency. + If so, it should eventually be handled in the m68k/sgs.h ASM_OUTPUT_OPCODE + macro, like the other SGS assembler quirks. -fnf */ + +#define FSGLDIV_USE_S /* Use fsgldiv.s, not fsgldiv.x */ +#define FSGLMUL_USE_S /* Use fsglmul.s, not fsglmul.x */ + +/* At end of a switch table, define LDnnn iff the symbol LInnn was defined. + Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" + fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results + we want. This difference can be accommodated by making the assembler + define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other + string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END + macro. (the Amiga assembler has this bug) */ + +#undef ASM_OUTPUT_CASE_END +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +do { \ + if (switch_table_difference_label_flag) \ + asm_fprintf ((FILE), "\t%s %LLD%d,%LL%d\n", SET_ASM_OP, (NUM), (NUM));\ + switch_table_difference_label_flag = 0; \ +} while (0) + +int switch_table_difference_label_flag; + +/* This definition of ASM_OUTPUT_ASCII is the same as the one in m68k/sgs.h, + which has been overridden by the one in svr4.h. However, we can't use + the one in svr4.h because the ASV assembler croaks on some of the + strings that it emits (such as .string "\"%s\"\n"). */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +{ \ + register int sp = 0, lp = 0, ch; \ + fprintf ((FILE), "\t%s ", BYTE_ASM_OP); \ + do { \ + ch = (PTR)[sp]; \ + if (ch > ' ' && ! (ch & 0x80) && ch != '\\') \ + { \ + fprintf ((FILE), "'%c", ch); \ + } \ + else \ + { \ + fprintf ((FILE), "0x%x", ch); \ + } \ + if (++sp < (LEN)) \ + { \ + if ((sp % 10) == 0) \ + { \ + fprintf ((FILE), "\n\t%s ", BYTE_ASM_OP); \ + } \ + else \ + { \ + putc (',', (FILE)); \ + } \ + } \ + } while (sp < (LEN)); \ + putc ('\n', (FILE)); \ +} + +/* Override these for the sake of an assembler bug: the ASV + assembler can't handle .LC0@GOT syntax. This pollutes the final + table for shared librarys but what's a poor soul to do; sigh... RFH */ + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + if (flag_pic && !strcmp(PREFIX,"LC")) \ + sprintf (LABEL, "*%s%%%d", PREFIX, NUM); \ + else \ + sprintf (LABEL, "*%s%s%d", LOCAL_LABEL_PREFIX, PREFIX, NUM) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + if (flag_pic && !strcmp(PREFIX,"LC")) \ + asm_fprintf (FILE, "%s%%%d:\n", PREFIX, NUM); \ + else \ + asm_fprintf (FILE, "%0L%s%d:\n", PREFIX, NUM) diff --git a/gcc/config/m68k/aux-crt1.c b/gcc/config/m68k/aux-crt1.c new file mode 100755 index 0000000..9ee529b --- /dev/null +++ b/gcc/config/m68k/aux-crt1.c @@ -0,0 +1,134 @@ +/* Startup code for A/UX + Copyright (C) 1996 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* This file is compiled three times to produce crt1.o, mcrt1.o, and + maccrt1.o. The final two are created by defining MCRT1 and MACCRT1 + respectively. */ + +#include <stdlib.h> +#ifdef MCRT1 +#include <unistd.h> +#include <mon.h> +#endif + +/* Extern function declarations */ + +extern void initfpu(void); +extern void __istart(void); +extern void __compatmode(void); +extern void _cleanup(void); +extern int main(int, char **, char **); +extern void exit(int) __attribute__((noreturn)); +extern void _exit(int) __attribute__((noreturn)); + +#ifdef MACCRT1 +extern void InitMac(void); +#endif +#ifdef MCRT1 +static void monitor_start(void); +#endif + +/* Global variables */ + +char **environ; +char *__splimit; /* address of top of stack */ + + +/* Initialize system and run */ + +void _start() __attribute__((noreturn)); +void _start() +{ + register int *fp __asm__("%a6"); + register char *d0 __asm__("%d0"); + char **argv; + int argc; + + __splimit = d0; + argc = fp[1]; + argv = (char **)&fp[2]; + environ = &argv[argc+1]; + + initfpu(); + __istart(); + __compatmode(); + + atexit(_cleanup); +#ifdef MCRT1 + monitor_start(); +#endif +#ifdef MACCRT1 + InitMac(); +#endif + + exit(main(argc, argv, environ)); +} + + +#ifdef MCRT1 +/* Start/Stop program monitor */ + +extern void monitor(void *, void *, WORD *, int, int); + +static WORD *monitor_buffer; + +static void monitor_cleanup(void) +{ + monitor(NULL, NULL, NULL, 0, 0); + free(monitor_buffer); +} + +static void monitor_start(void) +{ + extern int etext; + extern int stext __asm__(".text"); + + /* Choice of buffer size should be "no more than a few times + smaller than the program size" -- I don't believe that there + are any (useful) functions smaller than two insns (4 bytes) + so that is the scale factor used here */ + int len = (&etext - &stext + 1) / 4; + + monitor_buffer = (WORD *)calloc(len, sizeof(WORD)); + if (monitor_buffer == NULL) + { + static const char msg[] = "mcrt1: could not allocate monitor buffer\n"; + write(2, msg, sizeof(msg)-1); + _exit(-1); + } + + /* I'm not sure why the count cap at 600 -- but that is what A/UX does */ + monitor(&stext, &etext, monitor_buffer, len, 600); + + atexit(monitor_cleanup); +} +#endif /* MCRT1 */ diff --git a/gcc/config/m68k/aux-crt2.asm b/gcc/config/m68k/aux-crt2.asm new file mode 100755 index 0000000..062c16a --- /dev/null +++ b/gcc/config/m68k/aux-crt2.asm @@ -0,0 +1,42 @@ +/* More startup code for A/UX */ + +#include "tm.h" + +#ifdef USE_BIN_AS + file "crt2.s" + +/* The init section is used to support shared libraries */ + init + global __istart + +__istart: + link %fp,&-4 +#else + .file "crt2.s" + +/* The init section is used to support shared libraries */ +.section .init, "x" +.even +.globl __istart + +__istart: + link %fp,#-4 + +#ifndef USE_COLLECT2 +/* The ctors and dtors sections are used to support COFF collection of + c++ constructors and destructors */ +.section .ctors, "d" +.even +.globl __CTOR_LIST__ + +__CTOR_LIST__: + .long -1 + +.section .dtors, "d" +.even +.globl __DTOR_LIST__ + +__DTOR_LIST__: + .long -1 +#endif /* USE_COLLECT2 */ +#endif /* USE_BIN_AS */ diff --git a/gcc/config/m68k/aux-crtn.asm b/gcc/config/m68k/aux-crtn.asm new file mode 100755 index 0000000..ce63d7f --- /dev/null +++ b/gcc/config/m68k/aux-crtn.asm @@ -0,0 +1,26 @@ +/* More startup code for A/UX */ + +#include "tm.h" + +#ifdef USE_BIN_AS + file "crtn.s" + + init + + unlk %fp + rts +#else + .file "crtn.s" + +.section .init, "x" + unlk %fp + rts + +#ifndef USE_COLLECT2 +.section .ctors, "d" + .long 0 + +.section .dtors, "d" + .long 0 +#endif /* USE_COLLECT2 */ +#endif /* USE_BIN_AS */ diff --git a/gcc/config/m68k/aux-exit.c b/gcc/config/m68k/aux-exit.c new file mode 100755 index 0000000..fe06c77 --- /dev/null +++ b/gcc/config/m68k/aux-exit.c @@ -0,0 +1,99 @@ +/* Generic atexit() + Copyright (C) 1996 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Rather than come up with some ugly hack to make mcrt1 work, it is + better to just go ahead and provide atexit(). */ + + +#include <stdlib.h> + + +void exit(int) __attribute__((noreturn)); +void _exit(int) __attribute__((noreturn)); +void _cleanup(void); + + +#define FNS_PER_BLOCK 32 + +struct atexit_fn_block +{ + struct atexit_fn_block *next; + void (*fns[FNS_PER_BLOCK])(void); + short used; +}; + + +/* staticly allocate the first block */ +static struct atexit_fn_block atexit_fns; +static struct atexit_fn_block *current_block = &atexit_fns; + + +int atexit(void (*fn)(void)) +{ + if (current_block->used >= FNS_PER_BLOCK) + { + struct atexit_fn_block *new_block = + (struct atexit_fn_block *)malloc(sizeof(struct atexit_fn_block)); + if (new_block == NULL) + return -1; + + new_block->used = 0; + new_block->next = current_block; + current_block = new_block; + } + + current_block->fns[current_block->used++] = fn; + + return 0; +} + + +void exit(int status) +{ + struct atexit_fn_block *block = current_block, *old_block; + short i; + + while (1) + { + for (i = block->used; --i >= 0 ;) + (*block->fns[i])(); + if (block == &atexit_fns) + break; + /* I know what you are thinking -- we are about to exit, why free? + Because it is friendly to memory leak detectors, that's why. */ + old_block = block; + block = block->next; + free(old_block); + } + + _exit(status); +} diff --git a/gcc/config/m68k/aux-low.gld b/gcc/config/m68k/aux-low.gld new file mode 100755 index 0000000..d1bb2a9 --- /dev/null +++ b/gcc/config/m68k/aux-low.gld @@ -0,0 +1,38 @@ +/* GLD link script for building mac-compatible executables */ + +OUTPUT_FORMAT("coff-m68k") + +SEARCH_DIR(@tooldir@/lib); +SEARCH_DIR(@libdir@); +SEARCH_DIR(/lib); +SEARCH_DIR(/usr/lib); +SEARCH_DIR(@local_prefix@/lib); + +ENTRY(_start) + +SECTIONS +{ + .lowmem 0 (DSECT) : { + /usr/lib/low.o (.data) + } + .text 0x10000000 : { + *(.text) + *(.init) + *(.fini) + etext = .; + _etext = .; + } + .data ALIGN(0x40000) : { + *(.data) + *(.ctors) + *(.dtors) + edata = .; + _edata = .; + } + .bss : { + *(.bss) + *(COMMON) + end = .; + _end = .; + } +} diff --git a/gcc/config/m68k/aux-mcount.c b/gcc/config/m68k/aux-mcount.c new file mode 100755 index 0000000..1001c84 --- /dev/null +++ b/gcc/config/m68k/aux-mcount.c @@ -0,0 +1,69 @@ +/* Profiling support code for A/UX + Copyright (C) 1996 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* This routine is called at the beginning of functions compiled with -p + or -pg. The A/UX libraries call mcount%, but gas cannot generate + symbols with embedded percent signs. Previous ports of GCC to A/UX + have done things like (1) assemble a stub routine with the native + assembler, or (2) assemble a stub routine with gas and edit the object + file. This solution has the advantage that it can interoperate with + the A/UX version and can be used in an eventual port of glibc to A/UX. */ + +#ifndef __GNUC__ +#error This file uses GNU C extensions +#endif + +#include <mon.h> + +#ifdef IN_GCC +#include "tm.h" +#endif + +struct cnt *_countbase; + +#ifdef FUNCTION_PROFILER_SYMBOL +void __mcount() __asm__(FUNCTION_PROFILER_SYMBOL); +#endif + +void __mcount() +{ + register long **pfncnt __asm__("%a0"); + register long *fncnt = *pfncnt; + + if (!fncnt) + { + struct cnt *newcnt = _countbase++; + newcnt->fnpc = (char *)__builtin_return_address(0); + *pfncnt = fncnt = &newcnt->mcnt; + } + *fncnt += 1; +} diff --git a/gcc/config/m68k/auxas.h b/gcc/config/m68k/auxas.h new file mode 100755 index 0000000..794df51 --- /dev/null +++ b/gcc/config/m68k/auxas.h @@ -0,0 +1,189 @@ +/* Definitions for Motorola 680x0 running A/UX using /bin/as + Copyright (C) 1996, 1997 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. */ + +#define USE_BIN_AS + +#ifndef USE_COLLECT2 +#define USE_COLLECT2 +#endif + +#ifndef __ASSEMBLY__ + +#include "m68k/sgs.h" + +#define ASM_SPEC "%{m68030:-68030 }%{m68040:-68040 }" + +/* Modify AT&T SGS assembler syntax */ +/* A/UX's as doesn't do dots in pseudo-ops */ + +#define SDB_DEBUGGING_INFO + +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\ttext" + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\tdata\t1" + +#undef BYTE_ASM_OP +#define BYTE_ASM_OP "byte" + +#undef WORD_ASM_OP +#define WORD_ASM_OP "short" + +#undef LONG_ASM_OP +#define LONG_ASM_OP "long" + +#undef SPACE_ASM_OP +#define SPACE_ASM_OP "space" + +#undef ALIGN_ASM_OP +#define ALIGN_ASM_OP "align" + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "\tglobal" + +#undef SWBEG_ASM_OP +#define SWBEG_ASM_OP "swbeg" + +#undef SET_ASM_OP +#define SET_ASM_OP "set" + +#undef ASM_PN_FORMAT +#define ASM_PN_FORMAT "%s%%%d" + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "L%" + +#define ADDITIONAL_REGISTER_NAMES { "%a6", 14, "%a7", 15 } + +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf ((FILE), "\t%s ", LONG_ASM_OP), \ + output_addr_const ((FILE), (VALUE)), \ + fprintf ((FILE), "\n")) + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm\t", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm\t", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + output_file_directive ((FILE), main_input_filename) + +#undef ASM_OUTPUT_SOURCE_FILENAME +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) \ +( fputs ("\tfile\t", (FILE)), \ + output_quoted_string ((FILE), (NAME)), \ + fputc ('\n', (FILE)) ) + +#undef ASM_OUTPUT_CASE_FETCH +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname) \ + asm_fprintf (file, "10(%Rpc,%s.", regname) + +#define SGS_NO_LI + +/* Random macros describing parts of SDB data. */ + +#define PUT_SDB_SCL(a) \ + fprintf(asm_out_file, "\tscl\t%d%s", (a), SDB_DELIM) + +#define PUT_SDB_INT_VAL(a) \ + fprintf (asm_out_file, "\tval\t%d%s", (a), SDB_DELIM) + +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fprintf (asm_out_file, SDB_DELIM)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, SDB_DELIM); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s%s", a, SDB_DELIM) + +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) + +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o%s", a, SDB_DELIM) + +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d%s", a, SDB_DELIM) + +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") + +#define PUT_SDB_NEXT_DIM(a) fprintf(asm_out_file, "%d,", a) + +#define PUT_SDB_LAST_DIM(a) fprintf(asm_out_file, "%d%s", a, SDB_DELIM) + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, SDB_DELIM); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb%s\tval\t~%s\tscl\t100%s\tline\t%d%s\tendef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb%s\tval\t~%s\tscl\t100%s\tline\t%d%s\tendef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf%s\tval\t~%s\tscl\t101%s\tline\t%d%s\tendef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef%s\tval\t~%s\tscl\t101%s\tline\t%d%s\tendef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_EPILOGUE_END(NAME) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, NAME); \ + fprintf (asm_out_file, \ + "%s\tval\t~%s\tscl\t-1%s\tendef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM); } while (0) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINE) \ + fprintf((FILE), "\tln\t%d\n", \ + (sdb_begin_function_line > 1 ? \ + last_linenum - sdb_begin_function_line : 1)) + +#define ASM_MOV_INSN "mov.l" + +#define FUNCTION_PROFILER_SYMBOL "mcount%" + +#endif /* !__ASSEMBLY__ */ diff --git a/gcc/config/m68k/auxgas.h b/gcc/config/m68k/auxgas.h new file mode 100755 index 0000000..c2e0d56 --- /dev/null +++ b/gcc/config/m68k/auxgas.h @@ -0,0 +1,56 @@ +/* Definitions for Motorola 680x0 running A/UX using GAS + Copyright (C) 1996 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. */ + +#define USE_GAS + +#ifndef __ASSEMBLY__ + +#include "m68k/m68k.h" +#include "m68k/coff.h" + +#define ASM_SPEC "%{m68000:-Am68000 }%{m68030:-Am68030 }%{m68040:-Am68040 }" + +/* Output #ident as a .ident. */ +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +#ifdef IDENTIFY_WITH_IDENT +/* Put the GCC identification somewhere nicer, I think. + Does the COFF GDB use the "gcc2_complied." symbol anyway? */ +#define ASM_IDENTIFY_GCC(FILE) /* nothing */ +#define ASM_IDENTIFY_LANGUAGE(FILE) \ + fprintf (FILE, "\t.ident \"GCC (%s) %s\"\n", lang_identify(), version_string) +#endif + +#ifdef USE_COLLECT2 +#undef ASM_OUTPUT_CONSTRUCTOR +#undef ASM_OUTPUT_DESTRUCTOR +/* for the sake of link-level compatibility with /bin/as version */ +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL +#endif + +#define ADDITIONAL_REGISTER_NAMES { "%fp", 14, "%a7", 15 } + +#define ASM_MOV_INSN "movel" + +#define FUNCTION_PROFILER_SYMBOL "__mcount" + +#endif /* !__ASSEMBLY__ */ diff --git a/gcc/config/m68k/auxgld.h b/gcc/config/m68k/auxgld.h new file mode 100755 index 0000000..12c97af --- /dev/null +++ b/gcc/config/m68k/auxgld.h @@ -0,0 +1,29 @@ +/* Definitions for Motorola 680x0 running A/UX using GLD + Copyright (C) 1996 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. */ + +#define USE_GNU_LD + +#ifndef __ASSEMBLY__ + +#define LINK_SPEC \ +"%{p:-L/lib/libp -L/usr/lib/libp }%{pg:-L/lib/libp -L/usr/lib/libp }\ +%{smac:-T low.gld%s }" + +#endif /* !__ASSEMBLY__ */ diff --git a/gcc/config/m68k/auxld.h b/gcc/config/m68k/auxld.h new file mode 100755 index 0000000..932dd6a --- /dev/null +++ b/gcc/config/m68k/auxld.h @@ -0,0 +1,35 @@ +/* Definitions for Motorola 680x0 running A/UX using /bin/ld + Copyright (C) 1996 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. */ + +#define USE_BIN_LD + +#ifndef USE_COLLECT2 +#define USE_COLLECT2 +#endif + +#ifndef __ASSEMBLY__ + +#define LINK_SPEC \ +"%{p:-L/lib/libp -L/usr/lib/libp }%{pg:-L/lib/libp -L/usr/lib/libp }\ +%{smac:low.ld%s }%{!smac:shlib.ld%s }" + +#define SWITCHES_NEED_SPACES "o" + +#endif /* !__ASSEMBLY__ */ diff --git a/gcc/config/m68k/ccur-GAS.h b/gcc/config/m68k/ccur-GAS.h new file mode 100755 index 0000000..685eb97 --- /dev/null +++ b/gcc/config/m68k/ccur-GAS.h @@ -0,0 +1,129 @@ +/* Definitions of target machine for GNU compiler. Concurrent 68k version. + Copyright (C) 1987, 1988, 1995, 1996, 1997 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 1, 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. */ + +#ifndef MASSCOMP +#define MASSCOMP +#endif + +#ifndef CONCURRENT +#define CONCURRENT +#endif + +#ifndef __mc68000__ +#define __mc68000__ +#endif + +#ifndef __mc68020__ +#define __mc68020__ +#endif + +#define USE_GAS +#define MOVE_RATIO 100 + +#define SPACE_AFTER_L_OPTION +#define SWITCHES_NEED_SPACES "oL" + +/* See m68k.h. 7 means 68020 with 68881. */ +#define TARGET_DEFAULT (MASK_68040|MASK_BITFIELD|MASK_68881|MASK_68020) + +#include "m68k/m68k.h" + +#define SIZE_TYPE "int" + +/* for 68k machines this only needs to be TRUE for the 68000 */ + +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 + +/* Names to predefine in the preprocessor for this target machine. */ +#define CPP_PREDEFINES \ + "-Dmc68000 -Dmasscomp -DMASSCOMP -Dunix -DLANGUAGE_C -Dconcurrent -DCONCURRENT" + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, GNU GAS syntax)"); + +/* Discard internal local symbols beginning with 'L'. */ +#define LINK_SPEC "-X" + +/* Every structure or union's size must be a multiple of 4 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#undef BIGGEST_ALIGNMENT +#define BIGGEST_ALIGNMENT 32 + +/* Allocation boundary (in *bits*) for storing pointers in memory. */ +#undef POINTER_BOUNDARY +#define POINTER_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 32 + +/* Allocation boundary in bits for the code of a function */ +#undef FUNCTION_BOUNDARY +#define FUNCTION_BOUNDARY 32 + +/* Make strings long-word aligned so dhrystones will run faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Make arrays of chars word-aligned for the same reasons. */ +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + (TREE_CODE (TYPE) == ARRAY_TYPE \ + && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* This is BSD, so it wants DBX format. */ +#define DBX_DEBUGGING_INFO + +/* Override parts of m68k.h */ + +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 1, 1 } + +#undef REG_ALLOC_ORDER +#define REG_ALLOC_ORDER \ +{ 0, 1, 2, 3, 4, 5, 6, 7,\ + 8, 9, 10, 11, 12, 13, 14, 15, \ + 16, 17, 22, 23, 18, 19, 20, 21 } + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n.globl fltused\n"); + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ +{ int _LOG = LOG; \ + if (_LOG == 1) \ + fprintf (FILE, "\t.even\n"); \ + else if (_LOG == 2) \ + fprintf (FILE, "\t.align 4\n"); \ + else if (_LOG != 0) \ + fprintf (FILE, "\t.align %d\n", _LOG);\ +} + +/* crt0.c should use the vax-bsd style of entry, with a dummy arg. */ + +#define CRT0_DUMMIES bogus_fp, diff --git a/gcc/config/m68k/coff.h b/gcc/config/m68k/coff.h new file mode 100755 index 0000000..acd45e7 --- /dev/null +++ b/gcc/config/m68k/coff.h @@ -0,0 +1,176 @@ +/* Definitions of target machine for GNU compiler. + m68k series COFF object files and debugging, version. + Copyright (C) 1994, 1996, 1997 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. */ + +/* This file is included after m68k.h by CPU COFF specific files. It + is not a complete target itself. */ + +/* Generate sdb debugging information. */ + +#define SDB_DEBUGGING_INFO + +/* Output DBX (stabs) debugging information if using -gstabs. */ + +#include "dbxcoff.h" + +/* COFF symbols don't start with an underscore. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* Use a prefix for local labels, just to be on the save side. */ + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* Use a register prefix to avoid clashes with external symbols (classic + example: `extern char PC;' in termcap). */ + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +/* In the machine description we can't use %R, because it will not be seen + by ASM_FPRINTF. (Isn't that a design bug?). */ + +#undef REGISTER_PREFIX_MD +#define REGISTER_PREFIX_MD "%%" + +/* config/m68k.md has an explicit reference to the program counter, + prefix this by the register prefix. */ + +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp %%pc@(2,%0:l)"; \ + else \ + return "jmp %%pc@(2,%0:w)"; \ + } while (0) + +/* Here are the new register names. */ + +#undef REGISTER_NAMES +#ifndef SUPPORT_SUN_FPA +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7" } +#else /* SUPPORTED_SUN_FPA */ +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6", "%fpa7", \ + "%fpa8", "%fpa9", "%fpa10", "%fpa11", "%fpa12", "%fpa13", "%fpa14", "%fpa15", \ + "%fpa16", "%fpa17", "%fpa18", "%fpa19", "%fpa20", "%fpa21", "%fpa22", "%fpa23", \ + "%fpa24", "%fpa25", "%fpa26", "%fpa27", "%fpa28", "%fpa29", "%fpa30", "%fpa31" } +#endif /* defined SUPPORT_SUN_FPA */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + output_file_directive ((FILE), main_input_filename) + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as uninitialized global + data. */ + +#define BSS_SECTION_ASM_OP ".section\t.bss" + +/* A C statement (sans semicolon) to output to the stdio stream + FILE the assembler definition of uninitialized global DECL named + NAME whose size is SIZE bytes and alignment is ALIGN bytes. + Try to use asm_output_aligned_bss to implement this macro. */ + +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) + +/* Support generic sections */ + +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \ + fprintf((FILE), ".section\t%s,\"%c\"\n", (NAME), \ + (DECL) && (TREE_CODE (DECL) == FUNCTION_DECL || \ + DECL_READONLY_SECTION (DECL, RELOC)) ? 'x' : 'd') + +/* Support the ctors and dtors sections for g++. */ + +#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"x\"" +#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctors, in_dtors + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +#define INT_ASM_OP ".long" + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctors_section (); \ + fprintf (FILE, "\t%s\t ", INT_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtors_section (); \ + fprintf (FILE, "\t%s\t ", INT_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Don't assume anything about startfiles. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" diff --git a/gcc/config/m68k/crds.h b/gcc/config/m68k/crds.h new file mode 100755 index 0000000..441b285 --- /dev/null +++ b/gcc/config/m68k/crds.h @@ -0,0 +1,621 @@ +/* Definitions of target machine for GNU compiler; + Charles River Data Systems UNiverse/32. + Copyright (C) 1987, 1993, 1994, 1996, 1997 Free Software Foundation, Inc. + Contributed by Gary E. Miller (Gary_Edmunds_Miller@cup.portal.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS /* Uses SGS assembler */ +#define SGS_SWITCH_TABLES /* Different switch table handling */ +#define SGS_NO_LI /* Suppress jump table label usage */ +#define CRDS /* Charles River Data Systems assembler */ + +#include "m68k/m68k.h" + +/* Without STRUCTURE_SIZE_BOUNDARY, we can't ensure that structures are + aligned such that we can correctly extract bitfields from them. + Someone should check whether the usual compiler on the crds machine + provides the equivalent behavior of STRUCTURE_SIZE_BOUNDARY. */ +/* Set to 16 because all other m68k targets have it so */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* See m68k.h. 0 means 680[01]0 with no 68881. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT 0 + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* special flags to the unos assembler. */ + +#undef ASM_SPEC +#define ASM_SPEC "-g" + +#undef LIB_SPEC +#define LIB_SPEC "%{!p:%{!pg:-lunos}}%{p:-lc_p}%{pg:-lc_p}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mc68rt0.o%s}%{!p:c68rt0.o%s}}" + +/* CC1 spec */ +#if 0 +/* c.sac only used in _s_call_r() in libunos.a and malloc() in libmalloc.a */ +/* so we do not need to bother ! */ +#define CC1_SPEC "-fpcc-struct-return" +#endif + +/* -O2 for MAX optimization */ +#undef CC1_SPEC +#define CC1_SPEC "%{O2:-fstrength-reduce}" + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +/* #define SDB_DEBUGGING_INFO UNOS casm has no debugging :-( */ + +/* UNOS need stack probe :-( */ + +#if 0 +#define HAVE_probe 1 +#define gen_probe() gen_rtx(ASM_INPUT, VOIDmode, "tstb -2048(sp)\t;probe\n") +#else +#undef NEED_PROBE +#define NEED_PROBE (-2048) +#endif + +/* use memcpy, memset instead of bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Don't try to define `gcc_compiled.' since the assembler might not + accept symbols with periods and GDB doesn't run on this machine anyway. */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68k -DM68000 -Dmc68000 -Dunos -Dunix -D__motorola__ -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +/* Register in which address to store a structure value + is passed to a function. */ +/* unos uses ".comm c.sac" returns &c.sac in d0 */ +/* make pointer to c.sac ? +#undef STRUCT_VALUE_REGNUM +#define STRUCT_VALUE gen_rtx(MEM, Pmode, gen_rtx( , , ) ) +*/ + +#define BSS_SECTION_ASM_OP ".bss" + +/* Specify how to pad function arguments. + Value should be `upward', `downward' or `none'. + Same as the default, except no padding for large or variable-size args. */ + +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (((MODE) == BLKmode \ + ? ((TYPE) && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ + && int_size_in_bytes (TYPE) < PARM_BOUNDARY / BITS_PER_UNIT) \ + : GET_MODE_BITSIZE (MODE) < PARM_BOUNDARY) \ + ? downward : none) + +/* Override parts of m68k.h to fit the CRuDS assembler. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, CRDS/UNOS)"); + +/* Specify extra dir to search for include files. */ +#define SYSTEM_INCLUDE_DIR "/include" + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + fprintf (FILE, ";#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#undef ASM_APP_ON +#define ASM_APP_ON ";#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#undef ASM_APP_OFF +#define ASM_APP_OFF ";#NO_APP\n" + +/* The prefix for immediate operands. */ + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "$" + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "\t.long 0x%x, 0x%x\n", l[0], l[1]); \ + } while (0) + +/*unos has no .skip :-( */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t. = . + %u\n", (SIZE)); + +/* This says how to output an assembler line + to define a local common symbol. */ +/* should use bss_section instead of data_section but this makes casm die ? */ + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +{ data_section (); \ + if ((SIZE) > 1) fprintf (FILE, "\t.even\n"); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ":\t. = . + %u\n", (ROUNDED));} + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmovel %s,-(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmovel (sp)+,%s\n", reg_names[REGNO]) + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE, P , SIZE) \ +do { int i; \ + fprintf ((FILE), "\t.ascii \""); \ + for (i = 0; i < (SIZE); i++) \ + { \ + register int c = (P)[i]; \ + if (i != 0 && (i / 200) * 200 == i) \ + fprintf ((FILE), "\"\n\t.ascii \""); \ + if (c >= ' ' && c < 0177) { \ + if (c != '\"' && c != '\\') { \ + putc (c, (FILE)); \ + continue; \ + } \ + } \ + /* brain dead asm doesn't understand char escapes */ \ + fprintf ((FILE), "\"\n\t.byte\t%d\n\t.ascii \"", c); \ + } \ + fprintf ((FILE), "\"\n"); \ + } while (0) + + +/* Change all JBxx to Bxx. Also change all DBRA to DBF. + Also change divs.l, etc., to divs, etc. But don't change divsl.l. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); } \ + else if ((PTR)[0] == 'd') \ + { \ + if (!strncmp ((PTR), "dbra", 4)) \ + { fprintf ((FILE), "dbf"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "div", 3) && (PTR)[5] == ' ') \ + { fprintf ((FILE), "div%c", (PTR)[3]); (PTR) += 6; } \ + } \ +} + + +#if 0 +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the 68000, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax, $ in unos syntax). + '!' for the fpcr register (used in some float-to-fixed conversions). + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather + than directly). Second part of 'y' below. + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. + 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs + CONST_DOUBLE's as SunFPA constant RAM registers if + possible, so it should not be used except for the SunFPA. */ + +#undef PRINT_OPERAND_PUNCT_VALID_P +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!') + +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ int i; \ + if (CODE == '.') ; \ + else if (CODE == '#') fprintf (FILE, "$"); \ + else if (CODE == '-') fprintf (FILE, "-(sp)"); \ + else if (CODE == '+') fprintf (FILE, "(sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(sp)"); \ + else if (CODE == '!') fprintf (FILE, "fpcr"); \ + else if (CODE == '/') \ + ; \ + else if (GET_CODE (X) == REG) \ + { if (REGNO (X) < 16 && (CODE == 'y' || CODE == 'x') && GET_MODE (X) == DFmode) \ + fprintf (FILE, "%s:%s", reg_names[REGNO (X)], reg_names[REGNO (X)+1]); \ + else \ + fprintf (FILE, "%s", reg_names[REGNO (X)]); \ + } \ + else if (GET_CODE (X) == MEM) \ + { \ + output_address (XEXP (X, 0)); \ + if (CODE == 'd' && ! TARGET_68020 \ + && CONSTANT_ADDRESS_P (XEXP (X, 0))) \ + /* fprintf (FILE, ".l") */; \ + } \ + else if ((CODE == 'y' || CODE == 'w') \ + && GET_CODE(X) == CONST_DOUBLE \ + && (i = standard_sun_fpa_constant_p (X))) \ + fprintf (FILE, "%%%d", i & 0x1ff); \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { REAL_VALUE_TYPE r; long l; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + if (CODE == 'f') \ + ASM_OUTPUT_FLOAT_OPERAND (CODE, FILE, r); \ + else \ + { REAL_VALUE_TO_TARGET_SINGLE (r, l); \ + fprintf (FILE, "$0x%x", l); } } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { REAL_VALUE_TYPE r; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + ASM_OUTPUT_DOUBLE_OPERAND (FILE, r); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == XFmode) \ + { REAL_VALUE_TYPE r; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + ASM_OUTPUT_LONG_DOUBLE_OPERAND (FILE, r); } \ + else { putc ('$', FILE); output_addr_const (FILE, X); }} +#endif + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. */ +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "L%d-LI%d-2(pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "L%d-LI%d-2(pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%d-LI%d-2(pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (breg != 0 && ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, ":%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%d-LI%d-2(pc,%s.l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + do { fprintf (FILE, "\t; file\t"); \ + output_quoted_string (FILE, FILENAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\t; ln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* This macro generates the assembly code for function entry. + FILE is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This macro is responsible for + knowing which registers should not be saved even if used. */ + +/* Note that the order of the bit mask for fmovem is the opposite + of the order for movem! */ + +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + /* unos stack probe */ \ + if ( fsize > 30000 ) { \ + fprintf (FILE, "\tmovel sp,a0\n"); \ + fprintf (FILE, "\taddl $-%d,a0\n", 2048 + fsize); \ + fprintf (FILE, "\ttstb (a0)\n"); \ + } else { \ + fprintf (FILE, "\ttstb -%d(sp)\n", 2048 + fsize); \ + } \ + if (frame_pointer_needed) \ + { if (TARGET_68020 || fsize < 0x8000) \ + fprintf (FILE, "\tlink a6,$%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink a6,$0\n\tsubl $%d,sp\n", fsize); } \ + else if (fsize) \ + { \ + /* Adding negative number is faster on the 68040. */ \ + if (fsize + 4 < 0x8000) \ + { \ + fprintf (FILE, "\tadd.w #%d,sp\n", - (fsize + 4)); \ + } \ + else \ + { \ + fprintf (FILE, "\tadd.l #%d,sp\n", - (fsize + 4)); \ + } \ + } \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if ((mask & 0xff) != 0) \ + fprintf (FILE, "\tfmovem $0x%x,-(sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmovel %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovem $0x%x,-(sp)\n", mask); } + +/* Must put address in %a0 , not %d0 . -- LGM, 7/15/88 */ +/* UNOS ?? */ +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmovl &LP%%%d,%%a0\n\tjsr mcount\n", (LABEL_NO)) + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only. This is mandatory because + of alloca; we also take advantage of it to omit stack adjustments + before returning. */ + +#undef FUNCTION_EPILOGUE +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { fprintf (FILE, "\tmovel $%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmovel -%d(a6,a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovel (sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmovel -%d(a6),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovem -%d(a6,a0.l),$0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovem (sp)+,$0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovem -%d(a6),$0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem -%d(a6,a0.l),$0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem (sp)+,$0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem -%d(a6),$0x%x\n", \ + foffset + fsize, fmask); } \ + if (fpoffset != 0) \ + for (regno = 55; regno >= 24; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) { \ + if (big) \ + fprintf(FILE, "\tfpmoved -%d(a6,a0.l), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + else if (! frame_pointer_needed) \ + fprintf(FILE, "\tfpmoved (sp)+, %s\n", \ + reg_names[regno]); \ + else \ + fprintf(FILE, "\tfpmoved -%d(a6), %s\n", \ + fpoffset + fsize, reg_names[regno]); \ + fpoffset -= 8; \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk a6\n"); \ + else if (fsize) \ + { \ + if (fsize + 4 < 0x8000) \ + { \ + fprintf (FILE, "\tadd.w #%d,sp\n", fsize + 4); \ + } \ + else \ + { \ + fprintf (FILE, "\tadd.l #%d,sp\n", fsize + 4); \ + } \ + } \ + if (current_function_pops_args) \ + fprintf (FILE, "\trtd $%d\n", current_function_pops_args); \ + else fprintf (FILE, "\trts\n"); } + diff --git a/gcc/config/m68k/ctix.h b/gcc/config/m68k/ctix.h new file mode 100755 index 0000000..9c213fc --- /dev/null +++ b/gcc/config/m68k/ctix.h @@ -0,0 +1,48 @@ +/* Definitions of target machine for GNU compiler. + Convergent Technologies MiniFrame version, + using GAS and binutils with COFF encapsulation. + + Written by Ronald Cole + + Because the MiniFrame's C compiler is so completely lobotomized, + bootstrapping this is damn near impossible! + Write to me for information on obtaining the binaries... + + bug reports to csusac!unify!rjc@ucdavis.edu + + Copyright (C) 1990 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 "m68k/3b1g.h" + +/* Names to predefine in the preprocessor for this target machine. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -Dmc68k -Dunix -Dctix -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +/* Where to look for robotussinized startfiles. */ +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/gnu/" + +/* Generate calls to the MiniFrame's library (for speed). */ +#define DIVSI3_LIBCALL "ldiv" +#define UDIVSI3_LIBCALL "uldiv" +#define MODSI3_LIBCALL "lrem" +#define UMODSI3_LIBCALL "ulrem" +#define MULSI3_LIBCALL "lmul" +#define UMULSI3_LIBCALL "ulmul" diff --git a/gcc/config/m68k/dpx2.h b/gcc/config/m68k/dpx2.h new file mode 100755 index 0000000..b377974 --- /dev/null +++ b/gcc/config/m68k/dpx2.h @@ -0,0 +1,822 @@ +/* Definitions of target machine for GNU compiler. + Bull DPX/2 200 and 300 systems (m68k, SysVr3). + Copyright (C) 1987, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Frederic Pierresteguy (F.Pierresteguy@frcl.bull.fr). + +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. */ + + +#ifndef USE_GAS +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS_NO_LI /* Suppress jump table label usage */ +#define VERSADOS /* This is the name of the assembler we have */ +#endif + +#include "m68k/m68k.h" +#undef SELECT_RTX_SECTION +#include "svr3.h" + +/* See m68k.h. 7 means 68020 with 68881. + * We really have 68030 and 68882, + * but this will get us going. + */ +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +#define OBJECT_FORMAT_COFF +#define NO_SYS_SIGLIST + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif +/* + * define all the things the compiler should + */ +#ifdef ncl_mr +# define CPP_PREDEFINES "-Dunix -Dbull -DDPX2 -DSVR3 -Dmc68000 -Dmc68020 -Dncl_mr=1 -D_BULL_SOURCE -D_POSIX_SOURCE -D_XOPEN_SOURCE -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +#else +# ifdef ncl_el +# define CPP_PREDEFINES "-Dunix -Dbull -DDPX2 -DSVR3 -Dmc68000 -Dmc68020 -Dncl_el -D_BULL_SOURCE -D_POSIX_SOURCE -D_XOPEN_SOURCE -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +# else +# define CPP_PREDEFINES "-Dunix -Dbull -DDPX2 -DSVR3 -Dmc68000 -Dmc68020 -D_BULL_SOURCE -D_POSIX_SOURCE -D_XOPEN_SOURCE -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +# endif +#endif + +#undef CPP_SPEC +/* + * you can't get a DPX/2 without a 68882 but allow it + * to be ignored... + */ +# define __HAVE_68881__ 1 +# define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__ }" + +#define HAVE_ATEXIT +#undef DO_GLOBAL_CTORS_BODY /* don't use svr3.h version */ +#undef DO_GLOBAL_DTORS_BODY + +#ifndef USE_GAS +/* + * handle the native MOTOROLA VERSAdos assembler. + */ + +/* See m68k.h. 3 means 68020 with 68881 and no bitfield + * bitfield instructions do not seem to work a clean way. + */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_68881|MASK_68020) + +/* The native assembler doesn't support fmovecr. */ +#define NO_ASM_FMOVECR + +#undef EXTRA_SECTIONS +#undef EXTRA_SECTION_FUNCTIONS +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION data_section +#undef SELECT_SECTION +#undef SELECT_RTX_SECTION +#define fini_section() while (0) + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\tsection 15" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\tsection 15" +#undef INIT_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP "\tsection 14" +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\tsection 10" +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\tsection 15" + + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +#define REAL_ARITHMETIC + +#undef ASM_OUTPUT_SOURCE_FILENAME +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, NA) \ + do { fprintf ((FILE), "\t.file\t'%s'\n", (NA)); } while (0) + +/* Assembler pseudos to introduce constants of various size. */ + +#undef ASM_BYTE_OP +#define ASM_BYTE_OP "\tdc.b" +#undef ASM_LONG +#define ASM_LONG "\tdc.l" + +/* + * we don't seem to support any of: + * .globl + * .even + * .align + * .ascii + */ +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tdcb.b %u,0\n", (SIZE)) + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "\txdef" + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) >= 1) \ + fprintf (FILE, "\tds.w 0\n"); + + +#define STRING_LIMIT (0) +#undef ASM_APP_ON +#define ASM_APP_ON "" +#undef ASM_APP_OFF +#define ASM_APP_OFF "" +/* + * dc.b 'hello, world!' + * dc.b 10,0 + * is how we have to output "hello, world!\n" + */ +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(asm_out_file, p, thissize) \ + do { register int i, c, f=0, len=0; \ + for (i = 0; i < thissize; i++) { \ + c = p[i]; \ + if (c == '\'' || c < ' ' || c > 127) { \ + switch(f) { \ + case 0: /* need to output dc.b etc */ \ + fprintf(asm_out_file, "\tdc.b %d", c); \ + f=1; \ + break; \ + case 1: \ + fprintf(asm_out_file, ",%d", c); \ + break; \ + default: \ + /* close a string */ \ + fprintf(asm_out_file, "'\n\tdc.b %d", c); \ + f=1; \ + break; \ + } \ + } else { \ + switch(f) { \ + case 0: \ + fprintf(asm_out_file, "\tdc.b '%c", c); \ + f=2; \ + break; \ + case 2: \ + if (len >= 79) { \ + fprintf(asm_out_file, "'\n\tdc.b '%c", c); \ + len = 0; } \ + else \ + fprintf(asm_out_file, "%c", c); \ + break; \ + default: \ + len = 0; \ + fprintf(asm_out_file, "\n\tdc.b '%c", c); \ + f=2; \ + break; \ + } \ + } \ + len++; \ + } \ + if (f==2) \ + putc('\'', asm_out_file); \ + putc('\n', asm_out_file); } while (0) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", reg_names[REGNO]) + + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\t.def\t.bf%s\t.val\t*%s\t.scl\t101%s\t.line\t%d%s\t.endef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\t.def\t.ef%s\t.val\t*%s\t.scl\t101%s\t.line\t%d%s\t.endef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\t.def\t.bb%s\t.val\t*%s\t.scl\t100%s\t.line\t%d%s\t.endef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\t.def\t.eb%s\t.val\t*%s\t.scl\t100%s\t.line\t%d%s\t.endef\n", \ + SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM) + +#define PUT_SDB_EPILOGUE_END(NAME) + +/* Output type in decimal not in octal as done in sdbout.c */ +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\t.type\t0%d%s", a, SDB_DELIM) + +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ \ + register int regno; \ + register int mask = 0; \ + int num_saved_regs = 0, first = 1; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + \ + \ + if (frame_pointer_needed) \ + { \ + /* Adding negative number is faster on the 68040. */ \ + if (fsize < 0x8000 && !TARGET_68040) \ + { \ + fprintf (FILE, "\tlink %s,#%d\n", \ + reg_names[FRAME_POINTER_REGNUM], -fsize); \ + } \ + else if (TARGET_68020) \ + { \ + fprintf (FILE, "\tlink %s,#%d\n", \ + reg_names[FRAME_POINTER_REGNUM], -fsize); \ + } \ + else \ + { \ + fprintf (FILE, "\tlink %s,#0\n\tadd.l #%d,sp\n", \ + reg_names[FRAME_POINTER_REGNUM], -fsize); \ + } \ + } \ + else if (fsize) \ + { \ + /* Adding negative number is faster on the 68040. */ \ + if (fsize + 4 < 0x8000) \ + { \ + fprintf (FILE, "\tadd.w #%d,sp\n", - (fsize + 4)); \ + } \ + else \ + { \ + fprintf (FILE, "\tadd.l #%d,sp\n", - (fsize + 4)); \ + } \ + } \ + for (regno = 23; regno >= 16; regno--) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + if (first) { \ + fprintf (FILE, "\tfmovem.x %s", reg_names[regno]); \ + first = 0; \ + } \ + else fprintf (FILE, "/%s", reg_names[regno]); \ + if (!first) fprintf (FILE, ",-(sp)\n"); \ + \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { \ + mask |= 1 << (15 - regno); \ + num_saved_regs++; \ + } \ + if (frame_pointer_needed) \ + { \ + mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM)); \ + num_saved_regs--; \ + } \ + \ + \ + if (num_saved_regs <= 2) \ + { \ + /* Store each separately in the same order moveml uses. \ + Using two movel instructions instead of a single moveml \ + is about 15% faster for the 68020 and 68030 at no expense \ + in code size */ \ + \ + int i; \ + \ + /* Undo the work from above. */ \ + for (i = 0; i< 16; i++) \ + if (mask & (1 << i)) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[15 - i]); \ + } \ + else if (mask) \ + { \ + first = 1; \ + for (regno = 0; regno < 16; regno++) \ + if (mask & (1 << regno)) \ + if (first) { \ + fprintf (FILE, "\tmovem.l %s", reg_names[15 - regno]); \ + first = 0; \ + } \ + else fprintf (FILE, "/%s", reg_names[15 - regno]); \ + fprintf (FILE, ",-(sp)\n"); \ + } \ + if (flag_pic && current_function_uses_pic_offset_table) \ + { \ + fprintf (FILE, "\tmove.l #__GLOBAL_OFFSET_TABLE_, %s\n", \ + reg_names[PIC_OFFSET_TABLE_REGNUM]); \ + fprintf (FILE, "\tlea.l (pc,%s.l),%s\n", \ + reg_names[PIC_OFFSET_TABLE_REGNUM], \ + reg_names[PIC_OFFSET_TABLE_REGNUM]); \ + } \ +} + + +#undef FUNCTION_EPILOGUE +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ \ + register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset, fpoffset, first = 1; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + rtx insn = get_last_insn (); \ + \ + /* If the last insn was a BARRIER, we don't have to write any code. */ \ + if (GET_CODE (insn) == NOTE) \ + insn = prev_nonnote_insn (insn); \ + if (insn && GET_CODE (insn) == BARRIER) \ + { \ + /* Output just a no-op so that debuggers don't get confused \ + about which function the pc is in at this address. */ \ + fprintf (FILE, "\tnop\n"); \ + return; \ + } \ + \ + nregs = 0; fmask = 0; fpoffset = 0; \ + for (regno = 16; regno < 24; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { \ + nregs++; \ + fmask |= 1 << (23 - regno); \ + } \ + foffset = fpoffset + nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) \ + regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { \ + nregs++; \ + mask |= 1 << regno; \ + } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask || fpoffset)) \ + { \ + fprintf (FILE, "\tmove.l #%d,a0\n", -fsize); \ + fsize = 0, big = 1; \ + } \ + if (nregs <= 2) \ + { \ + /* Restore each separately in the same order moveml does. \ + Using two movel instructions instead of a single moveml \ + is about 15% faster for the 68020 and 68030 at no expense \ + in code size. */ \ + \ + int i; \ + \ + /* Undo the work from above. */ \ + for (i = 0; i< 16; i++) \ + if (mask & (1 << i)) \ + { \ + if (big) \ + { \ + fprintf (FILE, "\tmove.l -%d(%s,a0.l),%s\n", \ + offset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[i]); \ + } \ + else if (! frame_pointer_needed) \ + { \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", \ + reg_names[i]); \ + } \ + else \ + { \ + fprintf (FILE, "\tmove.l -%d(%s),%s\n", \ + offset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[i]); \ + } \ + offset = offset - 4; \ + } \ + } \ + else if (mask) \ + { \ + first = 1; \ + for (regno = 0; regno < 16; regno++) \ + if (mask & (1 << regno)) \ + if (first && big) { \ + fprintf (FILE, "\tmovem.l -%d(%s,a0.l),%s", \ + offset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else if (first && ! frame_pointer_needed) { \ + fprintf (FILE, "\tmovem.l (sp)+,%s", \ + offset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else if (first) { \ + fprintf (FILE, "\tmovem.l -%d(%s),%s", \ + offset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else \ + fprintf (FILE, "/%s", reg_names[regno]); \ + fprintf (FILE, "\n"); \ + } \ + if (fmask) \ + { \ + first = 1; \ + for (regno = 16; regno < 24; regno++) \ + if (fmask & (1 << (23 - regno))) \ + if (first && big) { \ + fprintf (FILE, "\tfmovem.x -%d(%s,a0.l),%s", \ + foffset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else if (first && ! frame_pointer_needed) { \ + fprintf (FILE, "\tfmovem.x (sp)+,%s", \ + foffset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else if (first) { \ + fprintf (FILE, "\tfmovem.x -%d(%s),%s", \ + foffset + fsize, \ + reg_names[FRAME_POINTER_REGNUM], \ + reg_names[regno]); \ + first = 0; \ + } \ + else fprintf (FILE, "/%s", reg_names[regno]); \ + fprintf (FILE, "\n"); \ + } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk %s\n", \ + reg_names[FRAME_POINTER_REGNUM]); \ + else if (fsize) \ + { \ + if (fsize + 4 < 0x8000) \ + { \ + fprintf (FILE, "\tadd.w #%d,sp\n", fsize + 4); \ + } \ + else \ + { \ + fprintf (FILE, "\tadd.l #%d,sp\n", fsize + 4); \ + } \ + } \ + if (current_function_pops_args) \ + fprintf (FILE, "\trtd #%d\n", current_function_pops_args); \ + else \ + fprintf (FILE, "\trts\n"); \ +} + +/* Translate Motorola opcodes such as `jbeq' + into VERSAdos opcodes such as `beq'. + Change `fbeq' to `fbseq', `fbne' to `fbsneq'. +*/ + +#undef ASM_OUTPUT_OPCODE +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fbeq", 4)) \ + { fprintf ((FILE), "fbseq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbsneq"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'b' && (PTR)[1] == 'f') \ + { \ + char *s; \ + if ((s = (char*)strchr ((PTR), '{'))) \ + while (*s != '}') { \ + if (*s == 'b') \ + /* hack, I replace it with R ie nothing */ \ + *s = '0'; \ + s++; } \ + } \ +} + +/* This is how to output a `long double' extended real constant. */ +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "\tdc.l $%x,$%x,$%x\n", l[0], l[1], l[2]); \ + else \ + fprintf (FILE, "\tdc.l $%lx,$%lx,$%lx\n", l[0], l[1], l[2]); \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE +#if 0 +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "\tdc.d %s\n", dstr); \ + } while (0) +#endif +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tdc.l $%x,$%x\n", l[0], l[1]); \ + } while (0) + + +/* This is how to output an assembler line defining a `float' constant. */ +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "\tdc.l $%x\n", l); \ + else \ + fprintf (FILE, "\tdc.l $%lx\n", l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tdc.l "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tdc.w "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#undef ASM_OUTPUT_CHAR +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tdc.b "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ +#undef ASM_OUTPUT_BYTE +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tdc.b $%x\n", (VALUE)) + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + asm_fprintf (FILE, "\tdc.l %LL%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\tdc.w %LL%d-%LL%d\n", VALUE, REL) + +/* Currently, JUMP_TABLES_IN_TEXT_SECTION must be defined in order to + keep switch tables in the text section. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE == 'f') \ + { \ + char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9g", dstr); \ + asm_fprintf ((FILE), "%I%s", dstr); \ + } \ + else \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I$%x", l); \ + else \ + asm_fprintf ((FILE), "%I$%lx", l); \ + } \ + } while (0) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (FILE, "%I%s", dstr); \ + } while (0) + +/* Note, long double immediate operands are not actually + generated by m68k.md. */ +#undef ASM_OUTPUT_LONG_DOUBLE_OPERAND +#define ASM_OUTPUT_LONG_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (FILE, "%I%s", dstr); \ + } while (0) + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + /*fprintf ((FILE), "\tsection 14\n"); */ \ + data_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align) \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\tdcb.b %u,0\n", (ROUNDED)); \ + /* fprintf ((FILE), "\tsection 10\n"); */ \ + } while (0) + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(.L%d,pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(.L%d,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF \ + && ! (flag_pic && breg == pic_offset_table_rtx)) \ + { \ + fprintf (FILE, "(.L%d,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + putc ('(', FILE); \ + if (addr != 0) \ + { \ + output_addr_const (FILE, addr); \ + putc (',', FILE); \ + } \ + fprintf (FILE, "%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(.L%d,pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + + +#endif /* ! use gas */ diff --git a/gcc/config/m68k/dpx2.ifile b/gcc/config/m68k/dpx2.ifile new file mode 100755 index 0000000..2c8acd8 --- /dev/null +++ b/gcc/config/m68k/dpx2.ifile @@ -0,0 +1,55 @@ +/* + * dpx2.ifile - for collectless G++ on Bull DPX/2 + * + * Peter Schauer <Peter.Schauer@regent.e-technik.tu-muenchen.dbp.de> + * + * Install this file as $prefix/gcc-lib/dpx2/VERSION/gcc.ifile + * and comment out the lines referring to COLLECT at the top + * of Makefile before building GCC. + * + * This file has been tested with gcc-2.2.2 on a DPX/2 340 + * running BOS 2.00.45, if it doesn't work for you, stick + * with collect. + * --sjg + */ +/* + * Ifile to link with memory configured at 0. + * BLOCK to an offset that leaves room for many headers ( the value + * here allows for a file header, an outheader, and up to 11 section + * headers on most systems. + * BIND to an address that excludes page 0 from being mapped. The value + * used for BLOCK should be or'd into this value. Here I'm setting BLOCK + * to 0x200 and BIND to ( 0x100000 | value_used_for(BLOCK) ) + * If you are using shared libraries, watch that you don't overlap the + * address ranges assigned for shared libs. + * + * GROUP BIND to a location in the next segment. Here, the only value + * that you should change (I think) is that within NEXT, which I've set + * to my hardware segment size. You can always use a larger size, but not + * a smaller one. + */ +SECTIONS +{ + .text BIND(0x100200) BLOCK (0x200) : + { + /* plenty of room for headers */ + *(.init) + *(.text) + _vfork = _fork; /* I got tired of editing peoples sloppy code */ + *(.fini) + } + GROUP BIND( NEXT(0x100000) + (ADDR(.text) + (SIZEOF(.text)) % 0x1000)): + { + .data : { + ___CTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.ctor) + . += 4 ; /* trailing NULL */ + ___DTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.dtor) + . += 4 ; /* trailing NULL */ + } + .bss : { } + } +} diff --git a/gcc/config/m68k/dpx2cdbx.h b/gcc/config/m68k/dpx2cdbx.h new file mode 100755 index 0000000..88a180e --- /dev/null +++ b/gcc/config/m68k/dpx2cdbx.h @@ -0,0 +1,31 @@ +/* Definitions for Bull dpx/2 200 and 300 with gas + using dbx-in-coff encapsulation. + Copyright (C) 1992, 1994 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "m68k/dpx2g.h" + +/* Use STABS debugging information inside COFF. */ +#ifndef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO +#endif + +/* Let sbd debugging be the default. */ +#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG diff --git a/gcc/config/m68k/dpx2g.h b/gcc/config/m68k/dpx2g.h new file mode 100755 index 0000000..ea5cd13 --- /dev/null +++ b/gcc/config/m68k/dpx2g.h @@ -0,0 +1,71 @@ +/* + * dpx2g.h - Bull DPX/2 200 and 300 systems (m68k, SysVr3) with gas + */ + +#define USE_GAS +#include "m68k/dpx2.h" + +#if 0 /* #ifndef USE_COLLECT2 */ + +/* We use set vectors for the constructors/destructors. */ + +#undef ASM_OUTPUT_CONSTRUCTOR +#undef ASM_OUTPUT_DESTRUCTOR + +/* Although the gas we use can create .ctor and .dtor sections from N_SETT + stabs, it does not support section directives, so we need to have the loader + define the lists. + */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +/* similar to default, but allows for the table defined by ld with gcc.ifile. + nptrs is always 0. So we need to instead check that __DTOR_LIST__[1] != 0. + The old check is left in so that the same macro can be used if and when + a future version of gas does support section directives. */ + +#define DO_GLOBAL_DTORS_BODY {int nptrs = *(int *)__DTOR_LIST__; int i; \ + if (nptrs == -1 || (__DTOR_LIST__[0] == 0 && __DTOR_LIST__[1] != 0)) \ + for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++); \ + for (i = nptrs; i >= 1; i--) \ + __DTOR_LIST__[i] (); } + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!r:gcc.ifile%s}\ + %{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}\ + huge.o%s" + +#endif /* !USE_COLLECT2 */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}\ + huge.o%s" + + +/* + * we are using GAS + */ +#undef EXTRA_SECTION_FUNCTIONS +#undef EXTRA_SECTIONS +/* Gas understands dollars in labels. */ +#undef NO_DOLLAR_IN_LABEL +/* GAS does not understand .ident so don't output anything for #ident. */ +#undef ASM_OUTPUT_IDENT + +#undef ASM_LONG +#define ASM_LONG "\t.long" + +/* + * put const's in the text section + */ +#define const_section() text_section() +#define fini_section() while (0) + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.data" +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.data" +#undef INIT_SECTION_ASM_OP + +/* end of dpx2g.h */ diff --git a/gcc/config/m68k/fpgnulib.c b/gcc/config/m68k/fpgnulib.c new file mode 100755 index 0000000..0559b62 --- /dev/null +++ b/gcc/config/m68k/fpgnulib.c @@ -0,0 +1,442 @@ +/* This is a stripped down version of floatlib.c. It supplies only those + functions which exist in libgcc, but for which there is not assembly + language versions in m68k/lb1sf68.asm. + + It also includes simplistic support for extended floats (by working in + double precision). You must compile this file again with -DEXTFLOAT + to get this support. */ + +/* +** gnulib support for software floating point. +** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved. +** Permission is granted to do *anything* you want with this file, +** commercial or otherwise, provided this message remains intact. So there! +** I would appreciate receiving any updates/patches/changes that anyone +** makes, and am willing to be the repository for said changes (am I +** making a big mistake?). +** +** Pat Wood +** Pipeline Associates, Inc. +** pipeline!phw@motown.com or +** sun!pipeline!phw or +** uunet!motown!pipeline!phw +** +** 05/01/91 -- V1.0 -- first release to gcc mailing lists +** 05/04/91 -- V1.1 -- added float and double prototypes and return values +** -- fixed problems with adding and subtracting zero +** -- fixed rounding in truncdfsf2 +** -- fixed SWAP define and tested on 386 +*/ + +/* +** The following are routines that replace the gnulib soft floating point +** routines that are called automatically when -msoft-float is selected. +** The support single and double precision IEEE format, with provisions +** for byte-swapped machines (tested on 386). Some of the double-precision +** routines work at full precision, but most of the hard ones simply punt +** and call the single precision routines, producing a loss of accuracy. +** long long support is not assumed or included. +** Overall accuracy is close to IEEE (actually 68882) for single-precision +** arithmetic. I think there may still be a 1 in 1000 chance of a bit +** being rounded the wrong way during a multiply. I'm not fussy enough to +** bother with it, but if anyone is, knock yourself out. +** +** Efficiency has only been addressed where it was obvious that something +** would make a big difference. Anyone who wants to do this right for +** best speed should go in and rewrite in assembler. +** +** I have tested this only on a 68030 workstation and 386/ix integrated +** in with -msoft-float. +*/ + +/* the following deal with IEEE single-precision numbers */ +#define EXCESS 126L +#define SIGNBIT 0x80000000L +#define HIDDEN (1L << 23L) +#define SIGN(fp) ((fp) & SIGNBIT) +#define EXP(fp) (((fp) >> 23L) & 0xFF) +#define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN) +#define PACK(s,e,m) ((s) | ((e) << 23L) | (m)) + +/* the following deal with IEEE double-precision numbers */ +#define EXCESSD 1022 +#define HIDDEND (1L << 20L) +#define EXPDBITS 11 +#define EXPDMASK 0x7FF +#define EXPD(fp) (((fp.l.upper) >> 20L) & 0x7FFL) +#define SIGND(fp) ((fp.l.upper) & SIGNBIT) +#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ + (fp.l.lower >> 22)) +#define MANTDMASK 0xFFFFF /* mask of upper part */ + +/* the following deal with IEEE extended-precision numbers */ +#define EXCESSX 16382 +#define HIDDENX (1L << 31L) +#define EXPXBITS 15 +#define EXPXMASK 0x7FFF +#define EXPX(fp) (((fp.l.upper) >> 16) & EXPXMASK) +#define SIGNX(fp) ((fp.l.upper) & SIGNBIT) +#define MANTXMASK 0x7FFFFFFF /* mask of upper part */ + +union double_long +{ + double d; + struct { + long upper; + unsigned long lower; + } l; +}; + +union float_long { + float f; + long l; +}; + +union long_double_long +{ + long double ld; + struct + { + long upper; + unsigned long middle; + unsigned long lower; + } l; +}; + +#ifndef EXTFLOAT + +/* convert int to double */ +double +__floatsidf (int a1) +{ + long sign = 0, exp = 31 + EXCESSD; + union double_long dl; + + if (!a1) + { + dl.l.upper = dl.l.lower = 0; + return dl.d; + } + + if (a1 < 0) + { + sign = SIGNBIT; + a1 = -a1; + if (a1 < 0) + { + dl.l.upper = SIGNBIT | ((32 + EXCESSD) << 20L); + dl.l.lower = 0; + return dl.d; + } + } + + while (a1 < 0x1000000) + { + a1 <<= 4; + exp -= 4; + } + + while (a1 < 0x40000000) + { + a1 <<= 1; + exp--; + } + + /* pack up and go home */ + dl.l.upper = sign; + dl.l.upper |= exp << 20L; + dl.l.upper |= (a1 >> 10L) & ~HIDDEND; + dl.l.lower = a1 << 22L; + + return dl.d; +} + +/* convert int to float */ +float +__floatsisf (int l) +{ + double foo = __floatsidf (l); + return foo; +} + +/* convert float to double */ +double +__extendsfdf2 (float a1) +{ + register union float_long fl1; + register union double_long dl; + register long exp; + + fl1.f = a1; + + if (!fl1.l) + { + dl.l.upper = dl.l.lower = 0; + return dl.d; + } + + dl.l.upper = SIGN (fl1.l); + exp = EXP (fl1.l) - EXCESS + EXCESSD; + dl.l.upper |= exp << 20; + dl.l.upper |= (MANT (fl1.l) & ~HIDDEN) >> 3; + dl.l.lower = MANT (fl1.l) << 29; + + return dl.d; +} + +/* convert double to float */ +float +__truncdfsf2 (double a1) +{ + register long exp; + register long mant; + register union float_long fl; + register union double_long dl1; + + dl1.d = a1; + + if (!dl1.l.upper && !dl1.l.lower) + return 0; + + exp = EXPD (dl1) - EXCESSD + EXCESS; + + /* shift double mantissa 6 bits so we can round */ + mant = MANTD (dl1) >> 6; + + /* now round and shift down */ + mant += 1; + mant >>= 1; + + /* did the round overflow? */ + if (mant & 0xFF000000) + { + mant >>= 1; + exp++; + } + + mant &= ~HIDDEN; + + /* pack up and go home */ + fl.l = PACK (SIGND (dl1), exp, mant); + return (fl.f); +} + +/* convert double to int */ +int +__fixdfsi (double a1) +{ + register union double_long dl1; + register long exp; + register long l; + + dl1.d = a1; + + if (!dl1.l.upper && !dl1.l.lower) + return 0; + + exp = EXPD (dl1) - EXCESSD - 31; + l = MANTD (dl1); + + if (exp > 0) + { + /* Return largest integer. */ + return SIGND (dl1) ? 0x80000000 : 0x7fffffff; + } + + if (exp <= -32) + return 0; + + /* shift down until exp = 0 */ + if (exp < 0) + l >>= -exp; + + return (SIGND (dl1) ? -l : l); +} + +/* convert float to int */ +int +__fixsfsi (float a1) +{ + double foo = a1; + return __fixdfsi (foo); +} + +#else /* EXTFLOAT */ + +/* Primitive extended precision floating point support. + + We assume all numbers are normalized, don't do any rounding, etc. */ + +/* Prototypes for the above in case we use them. */ +double __floatsidf (int); +float __floatsisf (int); +double __extendsfdf2 (float); +float __truncdfsf2 (double); +int __fixdfsi (double); +int __fixsfsi (float); + +/* convert double to long double */ +long double +__extenddfxf2 (double d) +{ + register union double_long dl; + register union long_double_long ldl; + register long exp; + + dl.d = d; + /*printf ("dfxf in: %g\n", d);*/ + + if (!dl.l.upper && !dl.l.lower) + return 0; + + ldl.l.upper = SIGND (dl); + exp = EXPD (dl) - EXCESSD + EXCESSX; + ldl.l.upper |= exp << 16; + ldl.l.middle = HIDDENX; + /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */ + ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20); + /* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */ + ldl.l.middle |= dl.l.lower >> (1 + 20); + /* 32 - 21: # bits of dl.l.lower in ldl.l.middle */ + ldl.l.lower = dl.l.lower << (32 - 21); + + /*printf ("dfxf out: %s\n", dumpxf (ldl.ld));*/ + return ldl.ld; +} + +/* convert long double to double */ +double +__truncxfdf2 (long double ld) +{ + register long exp; + register union double_long dl; + register union long_double_long ldl; + + ldl.ld = ld; + /*printf ("xfdf in: %s\n", dumpxf (ld));*/ + + if (!ldl.l.upper && !ldl.l.middle && !ldl.l.lower) + return 0; + + exp = EXPX (ldl) - EXCESSX + EXCESSD; + /* ??? quick and dirty: keep `exp' sane */ + if (exp >= EXPDMASK) + exp = EXPDMASK - 1; + dl.l.upper = SIGNX (ldl); + dl.l.upper |= exp << (32 - (EXPDBITS + 1)); + /* +1-1: add one for sign bit, but take one off for explicit-integer-bit */ + dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1); + dl.l.lower = (ldl.l.middle & MANTXMASK) << (32 - (EXPDBITS + 1 - 1)); + dl.l.lower |= ldl.l.lower >> (EXPDBITS + 1 - 1); + + /*printf ("xfdf out: %g\n", dl.d);*/ + return dl.d; +} + +/* convert a float to a long double */ +long double +__extendsfxf2 (float f) +{ + long double foo = __extenddfxf2 (__extendsfdf2 (f)); + return foo; +} + +/* convert a long double to a float */ +float +__truncxfsf2 (long double ld) +{ + float foo = __truncdfsf2 (__truncxfdf2 (ld)); + return foo; +} + +/* convert an int to a long double */ +long double +__floatsixf (int l) +{ + double foo = __floatsidf (l); + return foo; +} + +/* convert a long double to an int */ +int +__fixxfsi (long double ld) +{ + int foo = __fixdfsi ((double) ld); + return foo; +} + +/* The remaining provide crude math support by working in double precision. */ + +long double +__addxf3 (long double x1, long double x2) +{ + return (double) x1 + (double) x2; +} + +long double +__subxf3 (long double x1, long double x2) +{ + return (double) x1 - (double) x2; +} + +long double +__mulxf3 (long double x1, long double x2) +{ + return (double) x1 * (double) x2; +} + +long double +__divxf3 (long double x1, long double x2) +{ + return (double) x1 / (double) x2; +} + +long double +__negxf2 (long double x1) +{ + return - (double) x1; +} + +long +__cmpxf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__eqxf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__nexf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__ltxf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__lexf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__gtxf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +long +__gexf2 (long double x1, long double x2) +{ + return __cmpdf2 ((double) x1, (double) x2); +} + +#endif /* EXTFLOAT */ diff --git a/gcc/config/m68k/hp2bsd.h b/gcc/config/m68k/hp2bsd.h new file mode 100755 index 0000000..9090923 --- /dev/null +++ b/gcc/config/m68k/hp2bsd.h @@ -0,0 +1,78 @@ +/* Definitions of target machine for GNU compiler. HP 9000/200 68000 version. + Copyright (C) 1987, 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 "m68k/m68k.h" + +/* See m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT 0 + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68010 -Dhp200 -Dunix -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* Link with libg.a when debugging, for dbx's sake. */ + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Define subroutines to call to handle multiply, divide, and remainder. + These routines are built into the c-library on the hp200. + XXX What other routines from the c-library could we use? + The `*' prevents an underscore from being prepended by the compiler. */ + +#define DIVSI3_LIBCALL "*ldiv" +#define UDIVSI3_LIBCALL "*uldiv" +#define MODSI3_LIBCALL "*lrem" +#define UMODSI3_LIBCALL "*ulrem" +#define MULSI3_LIBCALL "*lmul" +#define UMULSI3_LIBCALL "*ulmul" + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 diff --git a/gcc/config/m68k/hp310.h b/gcc/config/m68k/hp310.h new file mode 100755 index 0000000..a9d24f4 --- /dev/null +++ b/gcc/config/m68k/hp310.h @@ -0,0 +1,36 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68010 version. */ + +/* See m68k.h. 0 means 68000 without 68881 and no bitfields. */ +#define TARGET_DEFAULT 0 + +#include "m68k/hp320.h" + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +#undef CPP_SPEC +#undef ASM_SPEC + +/* HP does not support a 68020 without a 68881 or a 68010 with a 68881. + However, -m68020 does not imply -m68881. You must specify both + if you want both. */ + +#ifdef HPUX_ASM + +#define CPP_SPEC "-D__HPUX_ASM__ %{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC "%{!m68020:%{!mc68020:+X}}" + +#else /* not HPUX_ASM */ + +#define CPP_SPEC "%{m68881: -D__HAVE_68881__}\ +%{m68020: -Dmc68020}%{mc68020: -Dmc68020}\ +%{!traditional:-D_INCLUDE__STDC__}" + +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +#endif /* not HPUX_ASM */ diff --git a/gcc/config/m68k/hp310g.h b/gcc/config/m68k/hp310g.h new file mode 100755 index 0000000..c07a73b --- /dev/null +++ b/gcc/config/m68k/hp310g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68010 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "m68k/hp310.h" diff --git a/gcc/config/m68k/hp320.h b/gcc/config/m68k/hp320.h new file mode 100755 index 0000000..9816502 --- /dev/null +++ b/gcc/config/m68k/hp320.h @@ -0,0 +1,642 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Copyright (C) 1987, 88, 93, 94, 95, 96, 1997 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. */ + +/* Define USE_GAS if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) + Undefine USE_GAS if you want GCC to feed the HP assembler. */ + +/* #define USE_GAS */ /* Use hp320g.h if you want this. */ + +/* Control assembler-syntax conditionals in m68k.md. */ + +#ifndef USE_GAS +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS /* Uses SGS assembler */ +#define SGS_CMP_ORDER /* Takes cmp operands in reverse order */ +#define HPUX_ASM + +#if !defined (CROSS_COMPILE) && !defined (NO_BUGS) +/* The assembler on HP 9k3xx machines running HPUX 8.0 doesn't translate + floating point constants behind some operands. The workaround is to + use hex constants. Reported by Thomas Nau (nau@medizin.uni-ulm.de). */ +#define AS_BUG_FLOATING_CONSTANT +/* The assembler on HP 9k3xx machines running HPUX 8.0 doesn't accept + labels followed by a text, data, or other section directive. Reported + by Thomas Nau (nau@medizin.uni-ulm.de). */ +#define AS_BUG_TRAILING_LABEL +#endif + +#endif /* not USE_GAS */ + +/* gcc.c should find libgcc.a itself rather than expecting linker to. */ +#define LINK_LIBGCC_SPECIAL +/* The arguments of -L must be a separate argv element. */ +#define SPACE_AFTER_L_OPTION +/* HP/UX doesn't have libg.a. */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" + +/* Be compatible with system stddef.h. */ +#define SIZE_TYPE "unsigned int" + +/* Use atexit for static constructors/destructors, instead of defining + our own exit function. */ +#define HAVE_ATEXIT + +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#ifdef HPUX_ASM + +#define ASM_SPEC "%{m68000:+X}%{mc68000:+X}" + +#define NO_DOT_IN_LABEL + +#if TARGET_DEFAULT & MASK_68881 /* -m68881 is the default */ + +/* These definitions differ from those used for GAS by defining __HPUX_ASM__. + This is needed because some programs, particularly GDB, need to + know which assembler is being used so that the correct `asm' + instructions can be used. */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}} -D_HPUX_SOURCE} -D__HPUX_ASM__" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}} -D_HPUX_SOURCE} -D__HPUX_ASM__" + +#endif /* default is -msoft-float */ + +#else /* not HPUX_ASM */ + +#if TARGET_DEFAULT & MASK_68881 /* -m68881 is the default */ + +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}} -D_HPUX_SOURCE}" + +#else /* default is -msoft-float */ + +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }\ +%{!ansi:%{!mc68000:%{!m68000:-Dmc68020}} -D_HPUX_SOURCE}" + +#endif /* default is -msoft-float */ + + +/* -m68000 requires special flags to the assembler. */ +#define ASM_SPEC \ + "%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" + +/* Tell GCC to put a space after -L when generating such options. */ +#define SPACE_AFTER_L_OPTION + +#endif /* Not HPUX_ASM */ + +/* Translate -static for HPUX linker. */ +#define LINK_SPEC "%{static:-a archive}" + +/* Names to predefine in the preprocessor for this target machine + (for non-strict-ANSI programs only). */ +/* These are the ones defined by HPUX cc, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dhp9000s200 -Dhp9000s300 -DPWB -Dhpux -Dunix -D__hp9000s300 -D__hp9000s200 -D__PWB -D__hpux -D__unix -D__motorola__ -Asystem(unix) -Asystem(hpux) -Acpu(m68k) -Amachine(m68k)" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* hpux doesn't use static area for struct returns. */ +#undef PCC_STATIC_STRUCT_RETURN + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +#if 0 /* No longer correct in HPUX version 6.5. */ +/* Function calls don't save any fp registers on hpux. */ +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1} +#endif /* 0 */ + +#ifdef HPUX_ASM + +/* Override parts of m68k.h to fit the HPUX assembler. */ + +#undef TARGET_VERSION +#undef REGISTER_NAMES +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_FILE_START +#undef ASM_APP_ON +#undef ASM_APP_OFF +#undef TEXT_SECTION_ASM_OP +#undef DATA_SECTION_ASM_OP +#undef READONLY_DATA_SECTION +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_SHORT +#undef ASM_OUTPUT_CHAR +#undef ASM_OUTPUT_BYTE +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SKIP +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#undef ASM_FORMAT_PRIVATE_NAME +#undef FUNCTION_PROFILER +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef GLOBAL_ASM_OP +#undef IMMEDIATE_PREFIX +#undef REGISTER_PREFIX + +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/hpux syntax)"); + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"} + +#define IMMEDIATE_PREFIX "&" +#define REGISTER_PREFIX "%" + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%d,%%a0\n\tjsr mcount\n", (LABEL_NO)); + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +/* For HPUX versions before 6.5, define this macro as empty. */ +#define ASM_FILE_START(FILE) \ + if (TARGET_68020) \ + { \ + if (TARGET_68881) \ + fprintf (FILE, "\tversion 3\n"); /* 68020 fp regs saved */ \ + else \ + fprintf (FILE, "\tversion 2\n"); /* 68020 no fp regs saved */ \ + } \ + else \ + fprintf (FILE, "\tversion 1\n"); /* 68010 */ + +#define ASM_APP_ON "" + +#define ASM_APP_OFF "" + +#ifdef AS_BUG_TRAILING_LABEL +#define TEXT_SECTION_ASM_OP "\tlalign\t1\ntext" +#define DATA_SECTION_ASM_OP "\tlalign\t1\ndata" +#else +#define TEXT_SECTION_ASM_OP "text" +#define DATA_SECTION_ASM_OP "data" +#endif +#define ASCII_DATA_ASM_OP "byte" + +/* This is the command to make the user-level label named NAME + defined for reference from other files. */ + +#define GLOBAL_ASM_OP "global" + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u,2\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO))) + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ +do{ if (PREFIX[0] == 'L' && PREFIX[1] == 'I') \ + fprintf(FILE, "\tset %s%d,.+2\n", PREFIX, NUM); \ + else \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM); \ +} while(0) + +#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "\tdouble 0f%s\n", dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(FILE, VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9g", dstr); \ + fprintf (FILE, "\tfloat 0f%s\n", dstr); \ + } while (0) + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tlong 0x%x,0x%x,0x%x\n", l[0], l[1], l[2]); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%d\n", VALUE) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\tshort L%d-L%d\n", VALUE, REL) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\tlalign 2\n"); \ + else if ((LOG) != 0) \ + abort (); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %u\n", (SIZE)) + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ + +#undef ASM_OUTPUT_FLOAT_OPERAND +#ifdef AS_BUG_FLOATING_CONSTANT +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "&0x%lx", l); \ + } while (0) +#else +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE == 'f') \ + { \ + char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9g", dstr); \ + fprintf ((FILE), "&0f%s", dstr); \ + } \ + else \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "&0x%lx", l); \ + } \ + } while (0) +#endif /* AS_BUG_FLOATING_CONSTANT */ + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "&0f%s", dstr); \ + } while (0) + +/* Note, long double immediate operands are not actually + generated by m68k.md. */ +#undef ASM_OUTPUT_LONG_DOUBLE_OPERAND +#define ASM_OUTPUT_LONG_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "&0f%s", dstr); \ + } while (0) + +#if 0 +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%fpcr"); \ + else if (CODE == '$') { if (TARGET_68040_ONLY) fprintf (FILE, "s"); } \ + else if (CODE == '&') { if (TARGET_68040_ONLY) fprintf (FILE, "d"); } \ + else if (CODE == '/') \ + fprintf (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 if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { REAL_VALUE_TYPE r; long l; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + PRINT_OPERAND_FLOAT (CODE, FILE, r, l); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { REAL_VALUE_TYPE r; char dstr[30]; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr); \ + fprintf (FILE, "&0f%s", dstr); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == XFmode) \ + { REAL_VALUE_TYPE r; char dstr[30]; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr); \ + fprintf (FILE, "&0f%s", dstr); } \ + else { putc ('&', FILE); output_addr_const (FILE, X); }} +#endif + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "L%d-LI%d(%%pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "L%d-LI%d(%%pc,%s.w)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#define ASM_OUTPUT_ASCII(f, p, size) \ +do { register int i; \ + int inside; \ + inside = FALSE; \ + for (i = 0; i < (size); i++) { \ + if (i % 8 == 0) { \ + if (i != 0) { \ + if (inside) \ + putc('"', (f)); \ + putc('\n', (f)); \ + inside = FALSE; \ + } \ + fprintf((f), "\t%s ", ASCII_DATA_ASM_OP); \ + } \ + if ((p)[i] < 32 || (p)[i] == '\\' || (p)[i] == '"' || (p)[i] == 127) { \ + if (inside) { \ + putc('"', (f)); \ + inside = FALSE; \ + } \ + if (i % 8 != 0) \ + putc(',', (f)); \ + fprintf((f), "%d", (p)[i]); \ + } else { \ + if (!inside) { \ + if (i % 8 != 0) \ + putc(',', (f)); \ + putc('"', (f)); \ + inside = TRUE; \ + } \ + putc((p)[i], (f)); \ + } \ + } \ + if (inside) \ + putc('"', (f)); \ + putc('\n', (f)); \ +} while (0) + +/* Translate Motorola opcodes such as `jbeq' + into SGS opcodes such as `beq.w'. + Delete the `e' in `move...' and `fmove'. + Change `ftst' to `ftest'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ +} + +/* Prevent output of `gcc_compiled.:'. */ + +#define ASM_IDENTIFY_GCC(FILE) + +#else /* not HPUX_ASM */ + +#undef FUNCTION_PROFILER + +/* HP-UX needs the call to mcount before the link instruction. + Copy the return address onto the stack before the call to fake it out. */ +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, \ + "\tmovel a6@(4),sp@-\n\tmovl #LP%d,a0\n\tjsr mcount\n\taddqw #4,sp\n", \ + (LABEL_NO)); + +#endif /* not HPUX_ASM */ + +/* In m68k svr4, a symbol_ref rtx can be a valid PIC operand if it is an + operand of a function call. */ +#undef LEGITIMATE_PIC_OPERAND_P +#define LEGITIMATE_PIC_OPERAND_P(X) \ + ((! symbolic_operand (X, VOIDmode) \ + && ! (GET_CODE (X) == CONST_DOUBLE && CONST_DOUBLE_MEM (X) \ + && GET_CODE (CONST_DOUBLE_MEM (X)) == MEM \ + && symbolic_operand (XEXP (CONST_DOUBLE_MEM (X), 0), VOIDmode))) \ + || (GET_CODE (X) == SYMBOL_REF && SYMBOL_REF_FLAG (X))) + +/* hpux8 and later have C++ compatible include files, so do not + pretend they are `extern "C"'. */ +#define NO_IMPLICIT_EXTERN_C diff --git a/gcc/config/m68k/hp320g.h b/gcc/config/m68k/hp320g.h new file mode 100755 index 0000000..1e93185 --- /dev/null +++ b/gcc/config/m68k/hp320g.h @@ -0,0 +1,12 @@ +/* Definitions of target machine for GNU compiler. HP-UX 68000/68020 version. + Use this file if GCC is supposed to work with the GNU assembler, + GNU linker and GNU debugger using DBX debugging information. + (In other words, much of HPUX has been cast aside.) */ + +/* This wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#define USE_GAS + +#include "m68k/hp320.h" diff --git a/gcc/config/m68k/hp3bsd.h b/gcc/config/m68k/hp3bsd.h new file mode 100755 index 0000000..34405f8 --- /dev/null +++ b/gcc/config/m68k/hp3bsd.h @@ -0,0 +1,44 @@ +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__ -D__HAVE_FPU__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68020 -Dhp300 -Dhp9000 -Dunix -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* Link with libg.a when debugging, for dbx's sake. */ + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 diff --git a/gcc/config/m68k/hp3bsd44.h b/gcc/config/m68k/hp3bsd44.h new file mode 100755 index 0000000..a3b652f --- /dev/null +++ b/gcc/config/m68k/hp3bsd44.h @@ -0,0 +1,53 @@ +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__ -D__HAVE_FPU__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dmc68020 -Dhp300 -Dhp9000 -Dunix -D__BSD_4_4__ -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* No more libg.a */ + +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" + +/* Make gcc agree with <machine/ansi.h> */ + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't use the `xsfoo;' construct in DBX output; this system + doesn't support it. */ + +#define DBX_NO_XREFS + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 diff --git a/gcc/config/m68k/hpux7.h b/gcc/config/m68k/hpux7.h new file mode 100755 index 0000000..ae584bd --- /dev/null +++ b/gcc/config/m68k/hpux7.h @@ -0,0 +1,7 @@ +/* tm.h for m68k running HPUX version 7. */ + +/* fletcher@cs.utexas.edu says this is needed. */ +#define NO_DOT_IN_LABEL +#define NO_BUGS + +#include "m68k/hp320.h" diff --git a/gcc/config/m68k/isi-nfp.h b/gcc/config/m68k/isi-nfp.h new file mode 100755 index 0000000..fbded9e --- /dev/null +++ b/gcc/config/m68k/isi-nfp.h @@ -0,0 +1,9 @@ +/* Define target machine as an ISI 68000/68020 with no 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +#include "m68k/isi.h" + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 diff --git a/gcc/config/m68k/isi.h b/gcc/config/m68k/isi.h new file mode 100755 index 0000000..a458cf9 --- /dev/null +++ b/gcc/config/m68k/isi.h @@ -0,0 +1,91 @@ +/* Definitions of target machine for GNU compiler. ISI 68000/68020 version. + Intended only for use with GAS, and not ISI's assembler, which is buggy + Copyright (C) 1988, 1996 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 "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +#if TARGET_DEFAULT & MASK_68881 +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a before libc.a. */ + +#define LIB_SPEC "%{!msoft-float:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}} \ +%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} %{g:-lg}" + +#else +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* If the 68881 is used, link must load libmc.a instead of libc.a */ + +#define LIB_SPEC "%{m68881:%{!p:%{!pg:-lmc}}%{p:-lmc_p}%{pg:-lmc_p}} \ +%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} %{g:-lg}" +#endif + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dmc68000 -Dis68k -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of m68k.h to fit the ISI 68k machine. */ + +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_VALUE_REGNO_P +#undef NEEDS_UNTYPED_CALL +#undef ASM_FILE_START + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* If TARGET_68881, return SF and DF values in f0 instead of d0. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + +/* 1 if N is a possible register number for a function value. + D0 may be used, and F0 as well if -m68881 is specified. */ + +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (TARGET_68881 && (N) == 16)) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#define NEEDS_UNTYPED_CALL 1 + +/* Also output something to cause the correct _doprnt to be loaded. */ +#define ASM_FILE_START(FILE) fprintf (FILE, "#NO_APP\n%s\n", TARGET_68881 ? ".globl fltused" : "") diff --git a/gcc/config/m68k/lb1sf68.asm b/gcc/config/m68k/lb1sf68.asm new file mode 100755 index 0000000..ef40a34 --- /dev/null +++ b/gcc/config/m68k/lb1sf68.asm @@ -0,0 +1,3904 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + +#ifdef L_floatex + +| This is an attempt at a decent floating point (single, double and +| extended double) code for the GNU C compiler. It should be easy to +| adapt to other compilers (but beware of the local labels!). + +| Starting date: 21 October, 1990 + +| It is convenient to introduce the notation (s,e,f) for a floating point +| number, where s=sign, e=exponent, f=fraction. We will call a floating +| point number fpn to abbreviate, independently of the precision. +| Let MAX_EXP be in each case the maximum exponent (255 for floats, 1023 +| for doubles and 16383 for long doubles). We then have the following +| different cases: +| 1. Normalized fpns have 0 < e < MAX_EXP. They correspond to +| (-1)^s x 1.f x 2^(e-bias-1). +| 2. Denormalized fpns have e=0. They correspond to numbers of the form +| (-1)^s x 0.f x 2^(-bias). +| 3. +/-INFINITY have e=MAX_EXP, f=0. +| 4. Quiet NaN (Not a Number) have all bits set. +| 5. Signaling NaN (Not a Number) have s=0, e=MAX_EXP, f=1. + +|============================================================================= +| exceptions +|============================================================================= + +| This is the floating point condition code register (_fpCCR): +| +| struct { +| short _exception_bits; +| short _trap_enable_bits; +| short _sticky_bits; +| short _rounding_mode; +| short _format; +| short _last_operation; +| union { +| float sf; +| double df; +| } _operand1; +| union { +| float sf; +| double df; +| } _operand2; +| } _fpCCR; + + .data + .even + + .globl SYM (_fpCCR) + +SYM (_fpCCR): +__exception_bits: + .word 0 +__trap_enable_bits: + .word 0 +__sticky_bits: + .word 0 +__rounding_mode: + .word ROUND_TO_NEAREST +__format: + .word NIL +__last_operation: + .word NOOP +__operand1: + .long 0 + .long 0 +__operand2: + .long 0 + .long 0 + +| Offsets: +EBITS = __exception_bits - SYM (_fpCCR) +TRAPE = __trap_enable_bits - SYM (_fpCCR) +STICK = __sticky_bits - SYM (_fpCCR) +ROUND = __rounding_mode - SYM (_fpCCR) +FORMT = __format - SYM (_fpCCR) +LASTO = __last_operation - SYM (_fpCCR) +OPER1 = __operand1 - SYM (_fpCCR) +OPER2 = __operand2 - SYM (_fpCCR) + +| The following exception types are supported: +INEXACT_RESULT = 0x0001 +UNDERFLOW = 0x0002 +OVERFLOW = 0x0004 +DIVIDE_BY_ZERO = 0x0008 +INVALID_OPERATION = 0x0010 + +| The allowed rounding modes are: +UNKNOWN = -1 +ROUND_TO_NEAREST = 0 | round result to nearest representable value +ROUND_TO_ZERO = 1 | round result towards zero +ROUND_TO_PLUS = 2 | round result towards plus infinity +ROUND_TO_MINUS = 3 | round result towards minus infinity + +| The allowed values of format are: +NIL = 0 +SINGLE_FLOAT = 1 +DOUBLE_FLOAT = 2 +LONG_FLOAT = 3 + +| The allowed values for the last operation are: +NOOP = 0 +ADD = 1 +MULTIPLY = 2 +DIVIDE = 3 +NEGATE = 4 +COMPARE = 5 +EXTENDSFDF = 6 +TRUNCDFSF = 7 + +|============================================================================= +| __clear_sticky_bits +|============================================================================= + +| The sticky bits are normally not cleared (thus the name), whereas the +| exception type and exception value reflect the last computation. +| This routine is provided to clear them (you can also write to _fpCCR, +| since it is globally visible). + + .globl SYM (__clear_sticky_bit) + + .text + .even + +| void __clear_sticky_bits(void); +SYM (__clear_sticky_bit): + lea SYM (_fpCCR),a0 +#ifndef __mcf5200__ + movew IMM (0),a0@(STICK) +#else + clr.w a0@(STICK) +#endif + rts + +|============================================================================= +| $_exception_handler +|============================================================================= + + .globl $_exception_handler + + .text + .even + +| This is the common exit point if an exception occurs. +| NOTE: it is NOT callable from C! +| It expects the exception type in d7, the format (SINGLE_FLOAT, +| DOUBLE_FLOAT or LONG_FLOAT) in d6, and the last operation code in d5. +| It sets the corresponding exception and sticky bits, and the format. +| Depending on the format if fills the corresponding slots for the +| operands which produced the exception (all this information is provided +| so if you write your own exception handlers you have enough information +| to deal with the problem). +| Then checks to see if the corresponding exception is trap-enabled, +| in which case it pushes the address of _fpCCR and traps through +| trap FPTRAP (15 for the moment). + +FPTRAP = 15 + +$_exception_handler: + lea SYM (_fpCCR),a0 + movew d7,a0@(EBITS) | set __exception_bits +#ifndef __mcf5200__ + orw d7,a0@(STICK) | and __sticky_bits +#else + movew a0@(STICK),d4 + orl d7,d4 + movew d4,a0@(STICK) +#endif + movew d6,a0@(FORMT) | and __format + movew d5,a0@(LASTO) | and __last_operation + +| Now put the operands in place: +#ifndef __mcf5200__ + cmpw IMM (SINGLE_FLOAT),d6 +#else + cmpl IMM (SINGLE_FLOAT),d6 +#endif + beq 1f + movel a6@(8),a0@(OPER1) + movel a6@(12),a0@(OPER1+4) + movel a6@(16),a0@(OPER2) + movel a6@(20),a0@(OPER2+4) + bra 2f +1: movel a6@(8),a0@(OPER1) + movel a6@(12),a0@(OPER2) +2: +| And check whether the exception is trap-enabled: +#ifndef __mcf5200__ + andw a0@(TRAPE),d7 | is exception trap-enabled? +#else + clrl d6 + movew a0@(TRAPE),d6 + andl d6,d7 +#endif + beq 1f | no, exit + pea SYM (_fpCCR) | yes, push address of _fpCCR + trap IMM (FPTRAP) | and trap +#ifndef __mcf5200__ +1: moveml sp@+,d2-d7 | restore data registers +#else +1: moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts +#endif /* L_floatex */ + +#ifdef L_mulsi3 + .text + .proc + .globl SYM (__mulsi3) +SYM (__mulsi3): + movew sp@(4), d0 /* x0 -> d0 */ + muluw sp@(10), d0 /* x0*y1 */ + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(8), d1 /* x1*y0 */ +#ifndef __mcf5200__ + addw d1, d0 +#else + addl d1, d0 +#endif + swap d0 + clrw d0 + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(10), d1 /* x1*y1 */ + addl d1, d0 + + rts +#endif /* L_mulsi3 */ + +#ifdef L_udivsi3 + .text + .proc + .globl SYM (__udivsi3) +SYM (__udivsi3): +#ifndef __mcf5200__ + movel d2, sp@- + movel sp@(12), d1 /* d1 = divisor */ + movel sp@(8), d0 /* d0 = dividend */ + + cmpl IMM (0x10000), d1 /* divisor >= 2 ^ 16 ? */ + jcc L3 /* then try next algorithm */ + movel d0, d2 + clrw d2 + swap d2 + divu d1, d2 /* high quotient in lower word */ + movew d2, d0 /* save high quotient */ + swap d0 + movew sp@(10), d2 /* get low dividend + high rest */ + divu d1, d2 /* low quotient */ + movew d2, d0 + jra L6 + +L3: movel d1, d2 /* use d2 as divisor backup */ +L4: lsrl IMM (1), d1 /* shift divisor */ + lsrl IMM (1), d0 /* shift dividend */ + cmpl IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ? */ + jcc L4 + divu d1, d0 /* now we have 16 bit divisor */ + andl IMM (0xffff), d0 /* mask out divisor, ignore remainder */ + +/* Multiply the 16 bit tentative quotient with the 32 bit divisor. Because of + the operand ranges, this might give a 33 bit product. If this product is + greater than the dividend, the tentative quotient was too large. */ + movel d2, d1 + mulu d0, d1 /* low part, 32 bits */ + swap d2 + mulu d0, d2 /* high part, at most 17 bits */ + swap d2 /* align high part with low part */ + tstw d2 /* high part 17 bits? */ + jne L5 /* if 17 bits, quotient was too large */ + addl d2, d1 /* add parts */ + jcs L5 /* if sum is 33 bits, quotient was too large */ + cmpl sp@(8), d1 /* compare the sum with the dividend */ + jls L6 /* if sum > dividend, quotient was too large */ +L5: subql IMM (1), d0 /* adjust quotient */ + +L6: movel sp@+, d2 + rts + +#else /* __mcf5200__ */ + +/* Coldfire implementation of non-restoring division algorithm from + Hennessy & Patterson, Appendix A. */ + link a6,IMM (-12) + moveml d2-d4,sp@ + movel a6@(8),d0 + movel a6@(12),d1 + clrl d2 | clear p + moveq IMM (31),d4 +L1: addl d0,d0 | shift reg pair (p,a) one bit left + addxl d2,d2 + movl d2,d3 | subtract b from p, store in tmp. + subl d1,d3 + jcs L2 | if no carry, + bset IMM (0),d0 | set the low order bit of a to 1, + movl d3,d2 | and store tmp in p. +L2: subql IMM (1),d4 + jcc L1 + moveml sp@,d2-d4 | restore data registers + unlk a6 | and return + rts +#endif /* __mcf5200__ */ + +#endif /* L_udivsi3 */ + +#ifdef L_divsi3 + .text + .proc + .globl SYM (__divsi3) +SYM (__divsi3): + movel d2, sp@- + + moveq IMM (1), d2 /* sign of result stored in d2 (=1 or =-1) */ + movel sp@(12), d1 /* d1 = divisor */ + jpl L1 + negl d1 +#ifndef __mcf5200__ + negb d2 /* change sign because divisor <0 */ +#else + negl d2 /* change sign because divisor <0 */ +#endif +L1: movel sp@(8), d0 /* d0 = dividend */ + jpl L2 + negl d0 +#ifndef __mcf5200__ + negb d2 +#else + negl d2 +#endif + +L2: movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */ + addql IMM (8), sp + + tstb d2 + jpl L3 + negl d0 + +L3: movel sp@+, d2 + rts +#endif /* L_divsi3 */ + +#ifdef L_umodsi3 + .text + .proc + .globl SYM (__umodsi3) +SYM (__umodsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) + addql IMM (8), sp + movel sp@(8), d1 /* d1 = divisor */ +#ifndef __mcf5200__ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql IMM (8), sp +#else + mulsl d1,d0 +#endif + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts +#endif /* L_umodsi3 */ + +#ifdef L_modsi3 + .text + .proc + .globl SYM (__modsi3) +SYM (__modsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__divsi3) + addql IMM (8), sp + movel sp@(8), d1 /* d1 = divisor */ +#ifndef __mcf5200__ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql IMM (8), sp +#else + mulsl d1,d0 +#endif + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts +#endif /* L_modsi3 */ + + +#ifdef L_double + + .globl SYM (_fpCCR) + .globl $_exception_handler + +QUIET_NaN = 0xffffffff + +D_MAX_EXP = 0x07ff +D_BIAS = 1022 +DBL_MAX_EXP = D_MAX_EXP - D_BIAS +DBL_MIN_EXP = 1 - D_BIAS +DBL_MANT_DIG = 53 + +INEXACT_RESULT = 0x0001 +UNDERFLOW = 0x0002 +OVERFLOW = 0x0004 +DIVIDE_BY_ZERO = 0x0008 +INVALID_OPERATION = 0x0010 + +DOUBLE_FLOAT = 2 + +NOOP = 0 +ADD = 1 +MULTIPLY = 2 +DIVIDE = 3 +NEGATE = 4 +COMPARE = 5 +EXTENDSFDF = 6 +TRUNCDFSF = 7 + +UNKNOWN = -1 +ROUND_TO_NEAREST = 0 | round result to nearest representable value +ROUND_TO_ZERO = 1 | round result towards zero +ROUND_TO_PLUS = 2 | round result towards plus infinity +ROUND_TO_MINUS = 3 | round result towards minus infinity + +| Entry points: + + .globl SYM (__adddf3) + .globl SYM (__subdf3) + .globl SYM (__muldf3) + .globl SYM (__divdf3) + .globl SYM (__negdf2) + .globl SYM (__cmpdf2) + + .text + .even + +| These are common routines to return and signal exceptions. + +Ld$den: +| Return and signal a denormalized number + orl d7,d0 + movew IMM (INEXACT_RESULT+UNDERFLOW),d7 + moveq IMM (DOUBLE_FLOAT),d6 + jmp $_exception_handler + +Ld$infty: +Ld$overflow: +| Return a properly signed INFINITY and set the exception flags + movel IMM (0x7ff00000),d0 + movel IMM (0),d1 + orl d7,d0 + movew IMM (INEXACT_RESULT+OVERFLOW),d7 + moveq IMM (DOUBLE_FLOAT),d6 + jmp $_exception_handler + +Ld$underflow: +| Return 0 and set the exception flags + movel IMM (0),d0 + movel d0,d1 + movew IMM (INEXACT_RESULT+UNDERFLOW),d7 + moveq IMM (DOUBLE_FLOAT),d6 + jmp $_exception_handler + +Ld$inop: +| Return a quiet NaN and set the exception flags + movel IMM (QUIET_NaN),d0 + movel d0,d1 + movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7 + moveq IMM (DOUBLE_FLOAT),d6 + jmp $_exception_handler + +Ld$div$0: +| Return a properly signed INFINITY and set the exception flags + movel IMM (0x7ff00000),d0 + movel IMM (0),d1 + orl d7,d0 + movew IMM (INEXACT_RESULT+DIVIDE_BY_ZERO),d7 + moveq IMM (DOUBLE_FLOAT),d6 + jmp $_exception_handler + +|============================================================================= +|============================================================================= +| double precision routines +|============================================================================= +|============================================================================= + +| A double precision floating point number (double) has the format: +| +| struct _double { +| unsigned int sign : 1; /* sign bit */ +| unsigned int exponent : 11; /* exponent, shifted by 126 */ +| unsigned int fraction : 52; /* fraction */ +| } double; +| +| Thus sizeof(double) = 8 (64 bits). +| +| All the routines are callable from C programs, and return the result +| in the register pair d0-d1. They also preserve all registers except +| d0-d1 and a0-a1. + +|============================================================================= +| __subdf3 +|============================================================================= + +| double __subdf3(double, double); +SYM (__subdf3): + bchg IMM (31),sp@(12) | change sign of second operand + | and fall through, so we always add +|============================================================================= +| __adddf3 +|============================================================================= + +| double __adddf3(double, double); +SYM (__adddf3): +#ifndef __mcf5200__ + link a6,IMM (0) | everything will be done in registers + moveml d2-d7,sp@- | save all data registers and a2 (but d0-d1) +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get first operand + movel a6@(12),d1 | + movel a6@(16),d2 | get second operand + movel a6@(20),d3 | + + movel d0,d7 | get d0's sign bit in d7 ' + addl d1,d1 | check and clear sign bit of a, and gain one + addxl d0,d0 | bit of extra precision + beq Ladddf$b | if zero return second operand + + movel d2,d6 | save sign in d6 + addl d3,d3 | get rid of sign bit and gain one bit of + addxl d2,d2 | extra precision + beq Ladddf$a | if zero return first operand + + andl IMM (0x80000000),d7 | isolate a's sign bit ' + swap d6 | and also b's sign bit ' +#ifndef __mcf5200__ + andw IMM (0x8000),d6 | + orw d6,d7 | and combine them into d7, so that a's sign ' + | bit is in the high word and b's is in the ' + | low word, so d6 is free to be used +#else + andl IMM (0x8000),d6 + orl d6,d7 +#endif + movel d7,a0 | now save d7 into a0, so d7 is free to + | be used also + +| Get the exponents and check for denormalized and/or infinity. + + movel IMM (0x001fffff),d6 | mask for the fraction + movel IMM (0x00200000),d7 | mask to put hidden bit back + + movel d0,d4 | + andl d6,d0 | get fraction in d0 + notl d6 | make d6 into mask for the exponent + andl d6,d4 | get exponent in d4 + beq Ladddf$a$den | branch if a is denormalized + cmpl d6,d4 | check for INFINITY or NaN + beq Ladddf$nf | + orl d7,d0 | and put hidden bit back +Ladddf$1: + swap d4 | shift right exponent so that it starts +#ifndef __mcf5200__ + lsrw IMM (5),d4 | in bit 0 and not bit 20 +#else + lsrl IMM (5),d4 | in bit 0 and not bit 20 +#endif +| Now we have a's exponent in d4 and fraction in d0-d1 ' + movel d2,d5 | save b to get exponent + andl d6,d5 | get exponent in d5 + beq Ladddf$b$den | branch if b is denormalized + cmpl d6,d5 | check for INFINITY or NaN + beq Ladddf$nf + notl d6 | make d6 into mask for the fraction again + andl d6,d2 | and get fraction in d2 + orl d7,d2 | and put hidden bit back +Ladddf$2: + swap d5 | shift right exponent so that it starts +#ifndef __mcf5200__ + lsrw IMM (5),d5 | in bit 0 and not bit 20 +#else + lsrl IMM (5),d5 | in bit 0 and not bit 20 +#endif + +| Now we have b's exponent in d5 and fraction in d2-d3. ' + +| The situation now is as follows: the signs are combined in a0, the +| numbers are in d0-d1 (a) and d2-d3 (b), and the exponents in d4 (a) +| and d5 (b). To do the rounding correctly we need to keep all the +| bits until the end, so we need to use d0-d1-d2-d3 for the first number +| and d4-d5-d6-d7 for the second. To do this we store (temporarily) the +| exponents in a2-a3. + +#ifndef __mcf5200__ + moveml a2-a3,sp@- | save the address registers +#else + movel a2,sp@- + movel a3,sp@- + movel a4,sp@- +#endif + + movel d4,a2 | save the exponents + movel d5,a3 | + + movel IMM (0),d7 | and move the numbers around + movel d7,d6 | + movel d3,d5 | + movel d2,d4 | + movel d7,d3 | + movel d7,d2 | + +| Here we shift the numbers until the exponents are the same, and put +| the largest exponent in a2. +#ifndef __mcf5200__ + exg d4,a2 | get exponents back + exg d5,a3 | + cmpw d4,d5 | compare the exponents +#else + movel d4,a4 | get exponents back + movel a2,d4 + movel a4,a2 + movel d5,a4 + movel a3,d5 + movel a4,a3 + cmpl d4,d5 | compare the exponents +#endif + beq Ladddf$3 | if equal don't shift ' + bhi 9f | branch if second exponent is higher + +| Here we have a's exponent larger than b's, so we have to shift b. We do +| this by using as counter d2: +1: movew d4,d2 | move largest exponent to d2 +#ifndef __mcf5200__ + subw d5,d2 | and subtract second exponent + exg d4,a2 | get back the longs we saved + exg d5,a3 | +#else + subl d5,d2 | and subtract second exponent + movel d4,a4 | get back the longs we saved + movel a2,d4 + movel a4,a2 + movel d5,a4 + movel a3,d5 + movel a4,a3 +#endif +| if difference is too large we don't shift (actually, we can just exit) ' +#ifndef __mcf5200__ + cmpw IMM (DBL_MANT_DIG+2),d2 +#else + cmpl IMM (DBL_MANT_DIG+2),d2 +#endif + bge Ladddf$b$small +#ifndef __mcf5200__ + cmpw IMM (32),d2 | if difference >= 32, shift by longs +#else + cmpl IMM (32),d2 | if difference >= 32, shift by longs +#endif + bge 5f +2: +#ifndef __mcf5200__ + cmpw IMM (16),d2 | if difference >= 16, shift by words +#else + cmpl IMM (16),d2 | if difference >= 16, shift by words +#endif + bge 6f + bra 3f | enter dbra loop + +4: +#ifndef __mcf5200__ + lsrl IMM (1),d4 + roxrl IMM (1),d5 + roxrl IMM (1),d6 + roxrl IMM (1),d7 +#else + lsrl IMM (1),d7 + btst IMM (0),d6 + beq 10f + bset IMM (31),d7 +10: lsrl IMM (1),d6 + btst IMM (0),d5 + beq 11f + bset IMM (31),d6 +11: lsrl IMM (1),d5 + btst IMM (0),d4 + beq 12f + bset IMM (31),d5 +12: lsrl IMM (1),d4 +#endif +3: +#ifndef __mcf5200__ + dbra d2,4b +#else + subql IMM (1),d2 + bpl 4b +#endif + movel IMM (0),d2 + movel d2,d3 + bra Ladddf$4 +5: + movel d6,d7 + movel d5,d6 + movel d4,d5 + movel IMM (0),d4 +#ifndef __mcf5200__ + subw IMM (32),d2 +#else + subl IMM (32),d2 +#endif + bra 2b +6: + movew d6,d7 + swap d7 + movew d5,d6 + swap d6 + movew d4,d5 + swap d5 + movew IMM (0),d4 + swap d4 +#ifndef __mcf5200__ + subw IMM (16),d2 +#else + subl IMM (16),d2 +#endif + bra 3b + +9: +#ifndef __mcf5200__ + exg d4,d5 + movew d4,d6 + subw d5,d6 | keep d5 (largest exponent) in d4 + exg d4,a2 + exg d5,a3 +#else + movel d5,d6 + movel d4,d5 + movel d6,d4 + subl d5,d6 + movel d4,a4 + movel a2,d4 + movel a4,a2 + movel d5,a4 + movel a3,d5 + movel a4,a3 +#endif +| if difference is too large we don't shift (actually, we can just exit) ' +#ifndef __mcf5200__ + cmpw IMM (DBL_MANT_DIG+2),d6 +#else + cmpl IMM (DBL_MANT_DIG+2),d6 +#endif + bge Ladddf$a$small +#ifndef __mcf5200__ + cmpw IMM (32),d6 | if difference >= 32, shift by longs +#else + cmpl IMM (32),d6 | if difference >= 32, shift by longs +#endif + bge 5f +2: +#ifndef __mcf5200__ + cmpw IMM (16),d6 | if difference >= 16, shift by words +#else + cmpl IMM (16),d6 | if difference >= 16, shift by words +#endif + bge 6f + bra 3f | enter dbra loop + +4: +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 +#else + lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + btst IMM (0),d1 + beq 11f + bset IMM (31),d2 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 12f + bset IMM (31),d1 +12: lsrl IMM (1),d0 +#endif +3: +#ifndef __mcf5200__ + dbra d6,4b +#else + subql IMM (1),d6 + bpl 4b +#endif + movel IMM (0),d7 + movel d7,d6 + bra Ladddf$4 +5: + movel d2,d3 + movel d1,d2 + movel d0,d1 + movel IMM (0),d0 +#ifndef __mcf5200__ + subw IMM (32),d6 +#else + subl IMM (32),d6 +#endif + bra 2b +6: + movew d2,d3 + swap d3 + movew d1,d2 + swap d2 + movew d0,d1 + swap d1 + movew IMM (0),d0 + swap d0 +#ifndef __mcf5200__ + subw IMM (16),d6 +#else + subl IMM (16),d6 +#endif + bra 3b +Ladddf$3: +#ifndef __mcf5200__ + exg d4,a2 + exg d5,a3 +#else + movel d4,a4 + movel a2,d4 + movel a4,a2 + movel d5,a4 + movel a3,d5 + movel a4,a3 +#endif +Ladddf$4: +| Now we have the numbers in d0--d3 and d4--d7, the exponent in a2, and +| the signs in a4. + +| Here we have to decide whether to add or subtract the numbers: +#ifndef __mcf5200__ + exg d7,a0 | get the signs + exg d6,a3 | a3 is free to be used +#else + movel d7,a4 + movel a0,d7 + movel a4,a0 + movel d6,a4 + movel a3,d6 + movel a4,a3 +#endif + movel d7,d6 | + movew IMM (0),d7 | get a's sign in d7 ' + swap d6 | + movew IMM (0),d6 | and b's sign in d6 ' + eorl d7,d6 | compare the signs + bmi Lsubdf$0 | if the signs are different we have + | to subtract +#ifndef __mcf5200__ + exg d7,a0 | else we add the numbers + exg d6,a3 | +#else + movel d7,a4 + movel a0,d7 + movel a4,a0 + movel d6,a4 + movel a3,d6 + movel a4,a3 +#endif + addl d7,d3 | + addxl d6,d2 | + addxl d5,d1 | + addxl d4,d0 | + + movel a2,d4 | return exponent to d4 + movel a0,d7 | + andl IMM (0x80000000),d7 | d7 now has the sign + +#ifndef __mcf5200__ + moveml sp@+,a2-a3 +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + +| Before rounding normalize so bit #DBL_MANT_DIG is set (we will consider +| the case of denormalized numbers in the rounding routine itself). +| As in the addition (not in the subtraction!) we could have set +| one more bit we check this: + btst IMM (DBL_MANT_DIG+1),d0 + beq 1f +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 + addw IMM (1),d4 +#else + lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + btst IMM (0),d1 + beq 11f + bset IMM (31),d2 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 12f + bset IMM (31),d1 +12: lsrl IMM (1),d0 + addl IMM (1),d4 +#endif +1: + lea Ladddf$5,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Ladddf$5: +| Put back the exponent and check for overflow +#ifndef __mcf5200__ + cmpw IMM (0x7ff),d4 | is the exponent big? +#else + cmpl IMM (0x7ff),d4 | is the exponent big? +#endif + bge 1f + bclr IMM (DBL_MANT_DIG-1),d0 +#ifndef __mcf5200__ + lslw IMM (4),d4 | put exponent back into position +#else + lsll IMM (4),d4 | put exponent back into position +#endif + swap d0 | +#ifndef __mcf5200__ + orw d4,d0 | +#else + orl d4,d0 | +#endif + swap d0 | + bra Ladddf$ret +1: + movew IMM (ADD),d5 + bra Ld$overflow + +Lsubdf$0: +| Here we do the subtraction. +#ifndef __mcf5200__ + exg d7,a0 | put sign back in a0 + exg d6,a3 | +#else + movel d7,a4 + movel a0,d7 + movel a4,a0 + movel d6,a4 + movel a3,d6 + movel a4,a3 +#endif + subl d7,d3 | + subxl d6,d2 | + subxl d5,d1 | + subxl d4,d0 | + beq Ladddf$ret$1 | if zero just exit + bpl 1f | if positive skip the following + movel a0,d7 | + bchg IMM (31),d7 | change sign bit in d7 + movel d7,a0 | + negl d3 | + negxl d2 | + negxl d1 | and negate result + negxl d0 | +1: + movel a2,d4 | return exponent to d4 + movel a0,d7 + andl IMM (0x80000000),d7 | isolate sign bit +#ifndef __mcf5200__ + moveml sp@+,a2-a3 | +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + +| Before rounding normalize so bit #DBL_MANT_DIG is set (we will consider +| the case of denormalized numbers in the rounding routine itself). +| As in the addition (not in the subtraction!) we could have set +| one more bit we check this: + btst IMM (DBL_MANT_DIG+1),d0 + beq 1f +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 + addw IMM (1),d4 +#else + lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + btst IMM (0),d1 + beq 11f + bset IMM (31),d2 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 12f + bset IMM (31),d1 +12: lsrl IMM (1),d0 + addl IMM (1),d4 +#endif +1: + lea Lsubdf$1,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Lsubdf$1: +| Put back the exponent and sign (we don't have overflow). ' + bclr IMM (DBL_MANT_DIG-1),d0 +#ifndef __mcf5200__ + lslw IMM (4),d4 | put exponent back into position +#else + lsll IMM (4),d4 | put exponent back into position +#endif + swap d0 | +#ifndef __mcf5200__ + orw d4,d0 | +#else + orl d4,d0 | +#endif + swap d0 | + bra Ladddf$ret + +| If one of the numbers was too small (difference of exponents >= +| DBL_MANT_DIG+1) we return the other (and now we don't have to ' +| check for finiteness or zero). +Ladddf$a$small: +#ifndef __mcf5200__ + moveml sp@+,a2-a3 +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + movel a6@(16),d0 + movel a6@(20),d1 + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | restore data registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts + +Ladddf$b$small: +#ifndef __mcf5200__ + moveml sp@+,a2-a3 +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + movel a6@(8),d0 + movel a6@(12),d1 + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | restore data registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts + +Ladddf$a$den: + movel d7,d4 | d7 contains 0x00200000 + bra Ladddf$1 + +Ladddf$b$den: + movel d7,d5 | d7 contains 0x00200000 + notl d6 + bra Ladddf$2 + +Ladddf$b: +| Return b (if a is zero) + movel d2,d0 + movel d3,d1 + bra 1f +Ladddf$a: + movel a6@(8),d0 + movel a6@(12),d1 +1: + movew IMM (ADD),d5 +| Check for NaN and +/-INFINITY. + movel d0,d7 | + andl IMM (0x80000000),d7 | + bclr IMM (31),d0 | + cmpl IMM (0x7ff00000),d0 | + bge 2f | + movel d0,d0 | check for zero, since we don't ' + bne Ladddf$ret | want to return -0 by mistake + bclr IMM (31),d7 | + bra Ladddf$ret | +2: + andl IMM (0x000fffff),d0 | check for NaN (nonzero fraction) + orl d1,d0 | + bne Ld$inop | + bra Ld$infty | + +Ladddf$ret$1: +#ifndef __mcf5200__ + moveml sp@+,a2-a3 | restore regs and exit +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + +Ladddf$ret: +| Normal exit. + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ + orl d7,d0 | put sign bit back +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +Ladddf$ret$den: +| Return a denormalized number. +#ifndef __mcf5200__ + lsrl IMM (1),d0 | shift right once more + roxrl IMM (1),d1 | +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 +#endif + bra Ladddf$ret + +Ladddf$nf: + movew IMM (ADD),d5 +| This could be faster but it is not worth the effort, since it is not +| executed very often. We sacrifice speed for clarity here. + movel a6@(8),d0 | get the numbers back (remember that we + movel a6@(12),d1 | did some processing already) + movel a6@(16),d2 | + movel a6@(20),d3 | + movel IMM (0x7ff00000),d4 | useful constant (INFINITY) + movel d0,d7 | save sign bits + movel d2,d6 | + bclr IMM (31),d0 | clear sign bits + bclr IMM (31),d2 | +| We know that one of them is either NaN of +/-INFINITY +| Check for NaN (if either one is NaN return NaN) + cmpl d4,d0 | check first a (d0) + bhi Ld$inop | if d0 > 0x7ff00000 or equal and + bne 2f + tstl d1 | d1 > 0, a is NaN + bne Ld$inop | +2: cmpl d4,d2 | check now b (d1) + bhi Ld$inop | + bne 3f + tstl d3 | + bne Ld$inop | +3: +| Now comes the check for +/-INFINITY. We know that both are (maybe not +| finite) numbers, but we have to check if both are infinite whether we +| are adding or subtracting them. + eorl d7,d6 | to check sign bits + bmi 1f + andl IMM (0x80000000),d7 | get (common) sign bit + bra Ld$infty +1: +| We know one (or both) are infinite, so we test for equality between the +| two numbers (if they are equal they have to be infinite both, so we +| return NaN). + cmpl d2,d0 | are both infinite? + bne 1f | if d0 <> d2 they are not equal + cmpl d3,d1 | if d0 == d2 test d3 and d1 + beq Ld$inop | if equal return NaN +1: + andl IMM (0x80000000),d7 | get a's sign bit ' + cmpl d4,d0 | test now for infinity + beq Ld$infty | if a is INFINITY return with this sign + bchg IMM (31),d7 | else we know b is INFINITY and has + bra Ld$infty | the opposite sign + +|============================================================================= +| __muldf3 +|============================================================================= + +| double __muldf3(double, double); +SYM (__muldf3): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get a into d0-d1 + movel a6@(12),d1 | + movel a6@(16),d2 | and b into d2-d3 + movel a6@(20),d3 | + movel d0,d7 | d7 will hold the sign of the product + eorl d2,d7 | + andl IMM (0x80000000),d7 | + movel d7,a0 | save sign bit into a0 + movel IMM (0x7ff00000),d7 | useful constant (+INFINITY) + movel d7,d6 | another (mask for fraction) + notl d6 | + bclr IMM (31),d0 | get rid of a's sign bit ' + movel d0,d4 | + orl d1,d4 | + beq Lmuldf$a$0 | branch if a is zero + movel d0,d4 | + bclr IMM (31),d2 | get rid of b's sign bit ' + movel d2,d5 | + orl d3,d5 | + beq Lmuldf$b$0 | branch if b is zero + movel d2,d5 | + cmpl d7,d0 | is a big? + bhi Lmuldf$inop | if a is NaN return NaN + beq Lmuldf$a$nf | we still have to check d1 and b ... + cmpl d7,d2 | now compare b with INFINITY + bhi Lmuldf$inop | is b NaN? + beq Lmuldf$b$nf | we still have to check d3 ... +| Here we have both numbers finite and nonzero (and with no sign bit). +| Now we get the exponents into d4 and d5. + andl d7,d4 | isolate exponent in d4 + beq Lmuldf$a$den | if exponent zero, have denormalized + andl d6,d0 | isolate fraction + orl IMM (0x00100000),d0 | and put hidden bit back + swap d4 | I like exponents in the first byte +#ifndef __mcf5200__ + lsrw IMM (4),d4 | +#else + lsrl IMM (4),d4 | +#endif +Lmuldf$1: + andl d7,d5 | + beq Lmuldf$b$den | + andl d6,d2 | + orl IMM (0x00100000),d2 | and put hidden bit back + swap d5 | +#ifndef __mcf5200__ + lsrw IMM (4),d5 | +#else + lsrl IMM (4),d5 | +#endif +Lmuldf$2: | +#ifndef __mcf5200__ + addw d5,d4 | add exponents + subw IMM (D_BIAS+1),d4 | and subtract bias (plus one) +#else + addl d5,d4 | add exponents + subl IMM (D_BIAS+1),d4 | and subtract bias (plus one) +#endif + +| We are now ready to do the multiplication. The situation is as follows: +| both a and b have bit 52 ( bit 20 of d0 and d2) set (even if they were +| denormalized to start with!), which means that in the product bit 104 +| (which will correspond to bit 8 of the fourth long) is set. + +| Here we have to do the product. +| To do it we have to juggle the registers back and forth, as there are not +| enough to keep everything in them. So we use the address registers to keep +| some intermediate data. + +#ifndef __mcf5200__ + moveml a2-a3,sp@- | save a2 and a3 for temporary use +#else + movel a2,sp@- + movel a3,sp@- + movel a4,sp@- +#endif + movel IMM (0),a2 | a2 is a null register + movel d4,a3 | and a3 will preserve the exponent + +| First, shift d2-d3 so bit 20 becomes bit 31: +#ifndef __mcf5200__ + rorl IMM (5),d2 | rotate d2 5 places right + swap d2 | and swap it + rorl IMM (5),d3 | do the same thing with d3 + swap d3 | + movew d3,d6 | get the rightmost 11 bits of d3 + andw IMM (0x07ff),d6 | + orw d6,d2 | and put them into d2 + andw IMM (0xf800),d3 | clear those bits in d3 +#else + moveq IMM (11),d7 | left shift d2 11 bits + lsll d7,d2 + movel d3,d6 | get a copy of d3 + lsll d7,d3 | left shift d3 11 bits + andl IMM (0xffe00000),d6 | get the top 11 bits of d3 + moveq IMM (21),d7 | right shift them 21 bits + lsrl d7,d6 + orl d6,d2 | stick them at the end of d2 +#endif + + movel d2,d6 | move b into d6-d7 + movel d3,d7 | move a into d4-d5 + movel d0,d4 | and clear d0-d1-d2-d3 (to put result) + movel d1,d5 | + movel IMM (0),d3 | + movel d3,d2 | + movel d3,d1 | + movel d3,d0 | + +| We use a1 as counter: + movel IMM (DBL_MANT_DIG-1),a1 +#ifndef __mcf5200__ + exg d7,a1 +#else + movel d7,a4 + movel a1,d7 + movel a4,a1 +#endif + +1: +#ifndef __mcf5200__ + exg d7,a1 | put counter back in a1 +#else + movel d7,a4 + movel a1,d7 + movel a4,a1 +#endif + addl d3,d3 | shift sum once left + addxl d2,d2 | + addxl d1,d1 | + addxl d0,d0 | + addl d7,d7 | + addxl d6,d6 | + bcc 2f | if bit clear skip the following +#ifndef __mcf5200__ + exg d7,a2 | +#else + movel d7,a4 + movel a2,d7 + movel a4,a2 +#endif + addl d5,d3 | else add a to the sum + addxl d4,d2 | + addxl d7,d1 | + addxl d7,d0 | +#ifndef __mcf5200__ + exg d7,a2 | +#else + movel d7,a4 + movel a2,d7 + movel a4,a2 +#endif +2: +#ifndef __mcf5200__ + exg d7,a1 | put counter in d7 + dbf d7,1b | decrement and branch +#else + movel d7,a4 + movel a1,d7 + movel a4,a1 + subql IMM (1),d7 + bpl 1b +#endif + + movel a3,d4 | restore exponent +#ifndef __mcf5200__ + moveml sp@+,a2-a3 +#else + movel sp@+,a4 + movel sp@+,a3 + movel sp@+,a2 +#endif + +| Now we have the product in d0-d1-d2-d3, with bit 8 of d0 set. The +| first thing to do now is to normalize it so bit 8 becomes bit +| DBL_MANT_DIG-32 (to do the rounding); later we will shift right. + swap d0 + swap d1 + movew d1,d0 + swap d2 + movew d2,d1 + swap d3 + movew d3,d2 + movew IMM (0),d3 +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 +#else + moveq IMM (29),d6 + lsrl IMM (3),d3 + movel d2,d7 + lsll d6,d7 + orl d7,d3 + lsrl IMM (3),d2 + movel d1,d7 + lsll d6,d7 + orl d7,d2 + lsrl IMM (3),d1 + movel d0,d7 + lsll d6,d7 + orl d7,d1 + lsrl IMM (3),d0 +#endif + +| Now round, check for over- and underflow, and exit. + movel a0,d7 | get sign bit back into d7 + movew IMM (MULTIPLY),d5 + + btst IMM (DBL_MANT_DIG+1-32),d0 + beq Lround$exit +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + addw IMM (1),d4 +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 + addl IMM (1),d4 +#endif + bra Lround$exit + +Lmuldf$inop: + movew IMM (MULTIPLY),d5 + bra Ld$inop + +Lmuldf$b$nf: + movew IMM (MULTIPLY),d5 + movel a0,d7 | get sign bit back into d7 + tstl d3 | we know d2 == 0x7ff00000, so check d3 + bne Ld$inop | if d3 <> 0 b is NaN + bra Ld$overflow | else we have overflow (since a is finite) + +Lmuldf$a$nf: + movew IMM (MULTIPLY),d5 + movel a0,d7 | get sign bit back into d7 + tstl d1 | we know d0 == 0x7ff00000, so check d1 + bne Ld$inop | if d1 <> 0 a is NaN + bra Ld$overflow | else signal overflow + +| If either number is zero return zero, unless the other is +/-INFINITY or +| NaN, in which case we return NaN. +Lmuldf$b$0: + movew IMM (MULTIPLY),d5 +#ifndef __mcf5200__ + exg d2,d0 | put b (==0) into d0-d1 + exg d3,d1 | and a (with sign bit cleared) into d2-d3 +#else + movel d2,d7 + movel d0,d2 + movel d7,d0 + movel d3,d7 + movel d1,d3 + movel d7,d1 +#endif + bra 1f +Lmuldf$a$0: + movel a6@(16),d2 | put b into d2-d3 again + movel a6@(20),d3 | + bclr IMM (31),d2 | clear sign bit +1: cmpl IMM (0x7ff00000),d2 | check for non-finiteness + bge Ld$inop | in case NaN or +/-INFINITY return NaN + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +| If a number is denormalized we put an exponent of 1 but do not put the +| hidden bit back into the fraction; instead we shift left until bit 21 +| (the hidden bit) is set, adjusting the exponent accordingly. We do this +| to ensure that the product of the fractions is close to 1. +Lmuldf$a$den: + movel IMM (1),d4 + andl d6,d0 +1: addl d1,d1 | shift a left until bit 20 is set + addxl d0,d0 | +#ifndef __mcf5200__ + subw IMM (1),d4 | and adjust exponent +#else + subl IMM (1),d4 | and adjust exponent +#endif + btst IMM (20),d0 | + bne Lmuldf$1 | + bra 1b + +Lmuldf$b$den: + movel IMM (1),d5 + andl d6,d2 +1: addl d3,d3 | shift b left until bit 20 is set + addxl d2,d2 | +#ifndef __mcf5200__ + subw IMM (1),d5 | and adjust exponent +#else + subql IMM (1),d5 | and adjust exponent +#endif + btst IMM (20),d2 | + bne Lmuldf$2 | + bra 1b + + +|============================================================================= +| __divdf3 +|============================================================================= + +| double __divdf3(double, double); +SYM (__divdf3): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get a into d0-d1 + movel a6@(12),d1 | + movel a6@(16),d2 | and b into d2-d3 + movel a6@(20),d3 | + movel d0,d7 | d7 will hold the sign of the result + eorl d2,d7 | + andl IMM (0x80000000),d7 + movel d7,a0 | save sign into a0 + movel IMM (0x7ff00000),d7 | useful constant (+INFINITY) + movel d7,d6 | another (mask for fraction) + notl d6 | + bclr IMM (31),d0 | get rid of a's sign bit ' + movel d0,d4 | + orl d1,d4 | + beq Ldivdf$a$0 | branch if a is zero + movel d0,d4 | + bclr IMM (31),d2 | get rid of b's sign bit ' + movel d2,d5 | + orl d3,d5 | + beq Ldivdf$b$0 | branch if b is zero + movel d2,d5 + cmpl d7,d0 | is a big? + bhi Ldivdf$inop | if a is NaN return NaN + beq Ldivdf$a$nf | if d0 == 0x7ff00000 we check d1 + cmpl d7,d2 | now compare b with INFINITY + bhi Ldivdf$inop | if b is NaN return NaN + beq Ldivdf$b$nf | if d2 == 0x7ff00000 we check d3 +| Here we have both numbers finite and nonzero (and with no sign bit). +| Now we get the exponents into d4 and d5 and normalize the numbers to +| ensure that the ratio of the fractions is around 1. We do this by +| making sure that both numbers have bit #DBL_MANT_DIG-32-1 (hidden bit) +| set, even if they were denormalized to start with. +| Thus, the result will satisfy: 2 > result > 1/2. + andl d7,d4 | and isolate exponent in d4 + beq Ldivdf$a$den | if exponent is zero we have a denormalized + andl d6,d0 | and isolate fraction + orl IMM (0x00100000),d0 | and put hidden bit back + swap d4 | I like exponents in the first byte +#ifndef __mcf5200__ + lsrw IMM (4),d4 | +#else + lsrl IMM (4),d4 | +#endif +Ldivdf$1: | + andl d7,d5 | + beq Ldivdf$b$den | + andl d6,d2 | + orl IMM (0x00100000),d2 + swap d5 | +#ifndef __mcf5200__ + lsrw IMM (4),d5 | +#else + lsrl IMM (4),d5 | +#endif +Ldivdf$2: | +#ifndef __mcf5200__ + subw d5,d4 | subtract exponents + addw IMM (D_BIAS),d4 | and add bias +#else + subl d5,d4 | subtract exponents + addl IMM (D_BIAS),d4 | and add bias +#endif + +| We are now ready to do the division. We have prepared things in such a way +| that the ratio of the fractions will be less than 2 but greater than 1/2. +| At this point the registers in use are: +| d0-d1 hold a (first operand, bit DBL_MANT_DIG-32=0, bit +| DBL_MANT_DIG-1-32=1) +| d2-d3 hold b (second operand, bit DBL_MANT_DIG-32=1) +| d4 holds the difference of the exponents, corrected by the bias +| a0 holds the sign of the ratio + +| To do the rounding correctly we need to keep information about the +| nonsignificant bits. One way to do this would be to do the division +| using four registers; another is to use two registers (as originally +| I did), but use a sticky bit to preserve information about the +| fractional part. Note that we can keep that info in a1, which is not +| used. + movel IMM (0),d6 | d6-d7 will hold the result + movel d6,d7 | + movel IMM (0),a1 | and a1 will hold the sticky bit + + movel IMM (DBL_MANT_DIG-32+1),d5 + +1: cmpl d0,d2 | is a < b? + bhi 3f | if b > a skip the following + beq 4f | if d0==d2 check d1 and d3 +2: subl d3,d1 | + subxl d2,d0 | a <-- a - b + bset d5,d6 | set the corresponding bit in d6 +3: addl d1,d1 | shift a by 1 + addxl d0,d0 | +#ifndef __mcf5200__ + dbra d5,1b | and branch back +#else + subql IMM (1), d5 + bpl 1b +#endif + bra 5f +4: cmpl d1,d3 | here d0==d2, so check d1 and d3 + bhi 3b | if d1 > d2 skip the subtraction + bra 2b | else go do it +5: +| Here we have to start setting the bits in the second long. + movel IMM (31),d5 | again d5 is counter + +1: cmpl d0,d2 | is a < b? + bhi 3f | if b > a skip the following + beq 4f | if d0==d2 check d1 and d3 +2: subl d3,d1 | + subxl d2,d0 | a <-- a - b + bset d5,d7 | set the corresponding bit in d7 +3: addl d1,d1 | shift a by 1 + addxl d0,d0 | +#ifndef __mcf5200__ + dbra d5,1b | and branch back +#else + subql IMM (1), d5 + bpl 1b +#endif + bra 5f +4: cmpl d1,d3 | here d0==d2, so check d1 and d3 + bhi 3b | if d1 > d2 skip the subtraction + bra 2b | else go do it +5: +| Now go ahead checking until we hit a one, which we store in d2. + movel IMM (DBL_MANT_DIG),d5 +1: cmpl d2,d0 | is a < b? + bhi 4f | if b < a, exit + beq 3f | if d0==d2 check d1 and d3 +2: addl d1,d1 | shift a by 1 + addxl d0,d0 | +#ifndef __mcf5200__ + dbra d5,1b | and branch back +#else + subql IMM (1), d5 + bpl 1b +#endif + movel IMM (0),d2 | here no sticky bit was found + movel d2,d3 + bra 5f +3: cmpl d1,d3 | here d0==d2, so check d1 and d3 + bhi 2b | if d1 > d2 go back +4: +| Here put the sticky bit in d2-d3 (in the position which actually corresponds +| to it; if you don't do this the algorithm loses in some cases). ' + movel IMM (0),d2 + movel d2,d3 +#ifndef __mcf5200__ + subw IMM (DBL_MANT_DIG),d5 + addw IMM (63),d5 + cmpw IMM (31),d5 +#else + subl IMM (DBL_MANT_DIG),d5 + addl IMM (63),d5 + cmpl IMM (31),d5 +#endif + bhi 2f +1: bset d5,d3 + bra 5f +#ifndef __mcf5200__ + subw IMM (32),d5 +#else + subl IMM (32),d5 +#endif +2: bset d5,d2 +5: +| Finally we are finished! Move the longs in the address registers to +| their final destination: + movel d6,d0 + movel d7,d1 + movel IMM (0),d3 + +| Here we have finished the division, with the result in d0-d1-d2-d3, with +| 2^21 <= d6 < 2^23. Thus bit 23 is not set, but bit 22 could be set. +| If it is not, then definitely bit 21 is set. Normalize so bit 22 is +| not set: + btst IMM (DBL_MANT_DIG-32+1),d0 + beq 1f +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + roxrl IMM (1),d2 + roxrl IMM (1),d3 + addw IMM (1),d4 +#else + lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + btst IMM (0),d1 + beq 11f + bset IMM (31),d2 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 12f + bset IMM (31),d1 +12: lsrl IMM (1),d0 + addl IMM (1),d4 +#endif +1: +| Now round, check for over- and underflow, and exit. + movel a0,d7 | restore sign bit to d7 + movew IMM (DIVIDE),d5 + bra Lround$exit + +Ldivdf$inop: + movew IMM (DIVIDE),d5 + bra Ld$inop + +Ldivdf$a$0: +| If a is zero check to see whether b is zero also. In that case return +| NaN; then check if b is NaN, and return NaN also in that case. Else +| return zero. + movew IMM (DIVIDE),d5 + bclr IMM (31),d2 | + movel d2,d4 | + orl d3,d4 | + beq Ld$inop | if b is also zero return NaN + cmpl IMM (0x7ff00000),d2 | check for NaN + bhi Ld$inop | + blt 1f | + tstl d3 | + bne Ld$inop | +1: movel IMM (0),d0 | else return zero + movel d0,d1 | + lea SYM (_fpCCR),a0 | clear exception flags + movew IMM (0),a0@ | +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | +#else + moveml sp@,d2-d7 | + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | + rts | + +Ldivdf$b$0: + movew IMM (DIVIDE),d5 +| If we got here a is not zero. Check if a is NaN; in that case return NaN, +| else return +/-INFINITY. Remember that a is in d0 with the sign bit +| cleared already. + movel a0,d7 | put a's sign bit back in d7 ' + cmpl IMM (0x7ff00000),d0 | compare d0 with INFINITY + bhi Ld$inop | if larger it is NaN + tstl d1 | + bne Ld$inop | + bra Ld$div$0 | else signal DIVIDE_BY_ZERO + +Ldivdf$b$nf: + movew IMM (DIVIDE),d5 +| If d2 == 0x7ff00000 we have to check d3. + tstl d3 | + bne Ld$inop | if d3 <> 0, b is NaN + bra Ld$underflow | else b is +/-INFINITY, so signal underflow + +Ldivdf$a$nf: + movew IMM (DIVIDE),d5 +| If d0 == 0x7ff00000 we have to check d1. + tstl d1 | + bne Ld$inop | if d1 <> 0, a is NaN +| If a is INFINITY we have to check b + cmpl d7,d2 | compare b with INFINITY + bge Ld$inop | if b is NaN or INFINITY return NaN + tstl d3 | + bne Ld$inop | + bra Ld$overflow | else return overflow + +| If a number is denormalized we put an exponent of 1 but do not put the +| bit back into the fraction. +Ldivdf$a$den: + movel IMM (1),d4 + andl d6,d0 +1: addl d1,d1 | shift a left until bit 20 is set + addxl d0,d0 +#ifndef __mcf5200__ + subw IMM (1),d4 | and adjust exponent +#else + subl IMM (1),d4 | and adjust exponent +#endif + btst IMM (DBL_MANT_DIG-32-1),d0 + bne Ldivdf$1 + bra 1b + +Ldivdf$b$den: + movel IMM (1),d5 + andl d6,d2 +1: addl d3,d3 | shift b left until bit 20 is set + addxl d2,d2 +#ifndef __mcf5200__ + subw IMM (1),d5 | and adjust exponent +#else + subql IMM (1),d5 | and adjust exponent +#endif + btst IMM (DBL_MANT_DIG-32-1),d2 + bne Ldivdf$2 + bra 1b + +Lround$exit: +| This is a common exit point for __muldf3 and __divdf3. When they enter +| this point the sign of the result is in d7, the result in d0-d1, normalized +| so that 2^21 <= d0 < 2^22, and the exponent is in the lower byte of d4. + +| First check for underlow in the exponent: +#ifndef __mcf5200__ + cmpw IMM (-DBL_MANT_DIG-1),d4 +#else + cmpl IMM (-DBL_MANT_DIG-1),d4 +#endif + blt Ld$underflow +| It could happen that the exponent is less than 1, in which case the +| number is denormalized. In this case we shift right and adjust the +| exponent until it becomes 1 or the fraction is zero (in the latter case +| we signal underflow and return zero). + movel d7,a0 | + movel IMM (0),d6 | use d6-d7 to collect bits flushed right + movel d6,d7 | use d6-d7 to collect bits flushed right +#ifndef __mcf5200__ + cmpw IMM (1),d4 | if the exponent is less than 1 we +#else + cmpl IMM (1),d4 | if the exponent is less than 1 we +#endif + bge 2f | have to shift right (denormalize) +1: +#ifndef __mcf5200__ + addw IMM (1),d4 | adjust the exponent + lsrl IMM (1),d0 | shift right once + roxrl IMM (1),d1 | + roxrl IMM (1),d2 | + roxrl IMM (1),d3 | + roxrl IMM (1),d6 | + roxrl IMM (1),d7 | + cmpw IMM (1),d4 | is the exponent 1 already? +#else + addl IMM (1),d4 | adjust the exponent + lsrl IMM (1),d7 + btst IMM (0),d6 + beq 13f + bset IMM (31),d7 +13: lsrl IMM (1),d6 + btst IMM (0),d3 + beq 14f + bset IMM (31),d6 +14: lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + btst IMM (0),d1 + beq 11f + bset IMM (31),d2 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 12f + bset IMM (31),d1 +12: lsrl IMM (1),d0 + cmpl IMM (1),d4 | is the exponent 1 already? +#endif + beq 2f | if not loop back + bra 1b | + bra Ld$underflow | safety check, shouldn't execute ' +2: orl d6,d2 | this is a trick so we don't lose ' + orl d7,d3 | the bits which were flushed right + movel a0,d7 | get back sign bit into d7 +| Now call the rounding routine (which takes care of denormalized numbers): + lea Lround$0,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Lround$0: +| Here we have a correctly rounded result (either normalized or denormalized). + +| Here we should have either a normalized number or a denormalized one, and +| the exponent is necessarily larger or equal to 1 (so we don't have to ' +| check again for underflow!). We have to check for overflow or for a +| denormalized number (which also signals underflow). +| Check for overflow (i.e., exponent >= 0x7ff). +#ifndef __mcf5200__ + cmpw IMM (0x07ff),d4 +#else + cmpl IMM (0x07ff),d4 +#endif + bge Ld$overflow +| Now check for a denormalized number (exponent==0): + movew d4,d4 + beq Ld$den +1: +| Put back the exponents and sign and return. +#ifndef __mcf5200__ + lslw IMM (4),d4 | exponent back to fourth byte +#else + lsll IMM (4),d4 | exponent back to fourth byte +#endif + bclr IMM (DBL_MANT_DIG-32-1),d0 + swap d0 | and put back exponent +#ifndef __mcf5200__ + orw d4,d0 | +#else + orl d4,d0 | +#endif + swap d0 | + orl d7,d0 | and sign also + + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +|============================================================================= +| __negdf2 +|============================================================================= + +| double __negdf2(double, double); +SYM (__negdf2): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movew IMM (NEGATE),d5 + movel a6@(8),d0 | get number to negate in d0-d1 + movel a6@(12),d1 | + bchg IMM (31),d0 | negate + movel d0,d2 | make a positive copy (for the tests) + bclr IMM (31),d2 | + movel d2,d4 | check for zero + orl d1,d4 | + beq 2f | if zero (either sign) return +zero + cmpl IMM (0x7ff00000),d2 | compare to +INFINITY + blt 1f | if finite, return + bhi Ld$inop | if larger (fraction not zero) is NaN + tstl d1 | if d2 == 0x7ff00000 check d1 + bne Ld$inop | + movel d0,d7 | else get sign and return INFINITY + andl IMM (0x80000000),d7 + bra Ld$infty +1: lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts +2: bclr IMM (31),d0 + bra 1b + +|============================================================================= +| __cmpdf2 +|============================================================================= + +GREATER = 1 +LESS = -1 +EQUAL = 0 + +| int __cmpdf2(double, double); +SYM (__cmpdf2): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- | save registers +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movew IMM (COMPARE),d5 + movel a6@(8),d0 | get first operand + movel a6@(12),d1 | + movel a6@(16),d2 | get second operand + movel a6@(20),d3 | +| First check if a and/or b are (+/-) zero and in that case clear +| the sign bit. + movel d0,d6 | copy signs into d6 (a) and d7(b) + bclr IMM (31),d0 | and clear signs in d0 and d2 + movel d2,d7 | + bclr IMM (31),d2 | + cmpl IMM (0x7fff0000),d0 | check for a == NaN + bhi Ld$inop | if d0 > 0x7ff00000, a is NaN + beq Lcmpdf$a$nf | if equal can be INFINITY, so check d1 + movel d0,d4 | copy into d4 to test for zero + orl d1,d4 | + beq Lcmpdf$a$0 | +Lcmpdf$0: + cmpl IMM (0x7fff0000),d2 | check for b == NaN + bhi Ld$inop | if d2 > 0x7ff00000, b is NaN + beq Lcmpdf$b$nf | if equal can be INFINITY, so check d3 + movel d2,d4 | + orl d3,d4 | + beq Lcmpdf$b$0 | +Lcmpdf$1: +| Check the signs + eorl d6,d7 + bpl 1f +| If the signs are not equal check if a >= 0 + tstl d6 + bpl Lcmpdf$a$gt$b | if (a >= 0 && b < 0) => a > b + bmi Lcmpdf$b$gt$a | if (a < 0 && b >= 0) => a < b +1: +| If the signs are equal check for < 0 + tstl d6 + bpl 1f +| If both are negative exchange them +#ifndef __mcf5200__ + exg d0,d2 + exg d1,d3 +#else + movel d0,d7 + movel d2,d0 + movel d7,d2 + movel d1,d7 + movel d3,d1 + movel d7,d3 +#endif +1: +| Now that they are positive we just compare them as longs (does this also +| work for denormalized numbers?). + cmpl d0,d2 + bhi Lcmpdf$b$gt$a | |b| > |a| + bne Lcmpdf$a$gt$b | |b| < |a| +| If we got here d0 == d2, so we compare d1 and d3. + cmpl d1,d3 + bhi Lcmpdf$b$gt$a | |b| > |a| + bne Lcmpdf$a$gt$b | |b| < |a| +| If we got here a == b. + movel IMM (EQUAL),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts +Lcmpdf$a$gt$b: + movel IMM (GREATER),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts +Lcmpdf$b$gt$a: + movel IMM (LESS),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +Lcmpdf$a$0: + bclr IMM (31),d6 + bra Lcmpdf$0 +Lcmpdf$b$0: + bclr IMM (31),d7 + bra Lcmpdf$1 + +Lcmpdf$a$nf: + tstl d1 + bne Ld$inop + bra Lcmpdf$0 + +Lcmpdf$b$nf: + tstl d3 + bne Ld$inop + bra Lcmpdf$1 + +|============================================================================= +| rounding routines +|============================================================================= + +| The rounding routines expect the number to be normalized in registers +| d0-d1-d2-d3, with the exponent in register d4. They assume that the +| exponent is larger or equal to 1. They return a properly normalized number +| if possible, and a denormalized number otherwise. The exponent is returned +| in d4. + +Lround$to$nearest: +| We now normalize as suggested by D. Knuth ("Seminumerical Algorithms"): +| Here we assume that the exponent is not too small (this should be checked +| before entering the rounding routine), but the number could be denormalized. + +| Check for denormalized numbers: +1: btst IMM (DBL_MANT_DIG-32),d0 + bne 2f | if set the number is normalized +| Normalize shifting left until bit #DBL_MANT_DIG-32 is set or the exponent +| is one (remember that a denormalized number corresponds to an +| exponent of -D_BIAS+1). +#ifndef __mcf5200__ + cmpw IMM (1),d4 | remember that the exponent is at least one +#else + cmpl IMM (1),d4 | remember that the exponent is at least one +#endif + beq 2f | an exponent of one means denormalized + addl d3,d3 | else shift and adjust the exponent + addxl d2,d2 | + addxl d1,d1 | + addxl d0,d0 | +#ifndef __mcf5200__ + dbra d4,1b | +#else + subql IMM (1), d4 + bpl 1b +#endif +2: +| Now round: we do it as follows: after the shifting we can write the +| fraction part as f + delta, where 1 < f < 2^25, and 0 <= delta <= 2. +| If delta < 1, do nothing. If delta > 1, add 1 to f. +| If delta == 1, we make sure the rounded number will be even (odd?) +| (after shifting). + btst IMM (0),d1 | is delta < 1? + beq 2f | if so, do not do anything + orl d2,d3 | is delta == 1? + bne 1f | if so round to even + movel d1,d3 | + andl IMM (2),d3 | bit 1 is the last significant bit + movel IMM (0),d2 | + addl d3,d1 | + addxl d2,d0 | + bra 2f | +1: movel IMM (1),d3 | else add 1 + movel IMM (0),d2 | + addl d3,d1 | + addxl d2,d0 +| Shift right once (because we used bit #DBL_MANT_DIG-32!). +2: +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 +#endif + +| Now check again bit #DBL_MANT_DIG-32 (rounding could have produced a +| 'fraction overflow' ...). + btst IMM (DBL_MANT_DIG-32),d0 + beq 1f +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + addw IMM (1),d4 +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 + addl IMM (1),d4 +#endif +1: +| If bit #DBL_MANT_DIG-32-1 is clear we have a denormalized number, so we +| have to put the exponent to zero and return a denormalized number. + btst IMM (DBL_MANT_DIG-32-1),d0 + beq 1f + jmp a0@ +1: movel IMM (0),d4 + jmp a0@ + +Lround$to$zero: +Lround$to$plus: +Lround$to$minus: + jmp a0@ +#endif /* L_double */ + +#ifdef L_float + + .globl SYM (_fpCCR) + .globl $_exception_handler + +QUIET_NaN = 0xffffffff +SIGNL_NaN = 0x7f800001 +INFINITY = 0x7f800000 + +F_MAX_EXP = 0xff +F_BIAS = 126 +FLT_MAX_EXP = F_MAX_EXP - F_BIAS +FLT_MIN_EXP = 1 - F_BIAS +FLT_MANT_DIG = 24 + +INEXACT_RESULT = 0x0001 +UNDERFLOW = 0x0002 +OVERFLOW = 0x0004 +DIVIDE_BY_ZERO = 0x0008 +INVALID_OPERATION = 0x0010 + +SINGLE_FLOAT = 1 + +NOOP = 0 +ADD = 1 +MULTIPLY = 2 +DIVIDE = 3 +NEGATE = 4 +COMPARE = 5 +EXTENDSFDF = 6 +TRUNCDFSF = 7 + +UNKNOWN = -1 +ROUND_TO_NEAREST = 0 | round result to nearest representable value +ROUND_TO_ZERO = 1 | round result towards zero +ROUND_TO_PLUS = 2 | round result towards plus infinity +ROUND_TO_MINUS = 3 | round result towards minus infinity + +| Entry points: + + .globl SYM (__addsf3) + .globl SYM (__subsf3) + .globl SYM (__mulsf3) + .globl SYM (__divsf3) + .globl SYM (__negsf2) + .globl SYM (__cmpsf2) + +| These are common routines to return and signal exceptions. + + .text + .even + +Lf$den: +| Return and signal a denormalized number + orl d7,d0 + movew IMM (INEXACT_RESULT+UNDERFLOW),d7 + moveq IMM (SINGLE_FLOAT),d6 + jmp $_exception_handler + +Lf$infty: +Lf$overflow: +| Return a properly signed INFINITY and set the exception flags + movel IMM (INFINITY),d0 + orl d7,d0 + movew IMM (INEXACT_RESULT+OVERFLOW),d7 + moveq IMM (SINGLE_FLOAT),d6 + jmp $_exception_handler + +Lf$underflow: +| Return 0 and set the exception flags + movel IMM (0),d0 + movew IMM (INEXACT_RESULT+UNDERFLOW),d7 + moveq IMM (SINGLE_FLOAT),d6 + jmp $_exception_handler + +Lf$inop: +| Return a quiet NaN and set the exception flags + movel IMM (QUIET_NaN),d0 + movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7 + moveq IMM (SINGLE_FLOAT),d6 + jmp $_exception_handler + +Lf$div$0: +| Return a properly signed INFINITY and set the exception flags + movel IMM (INFINITY),d0 + orl d7,d0 + movew IMM (INEXACT_RESULT+DIVIDE_BY_ZERO),d7 + moveq IMM (SINGLE_FLOAT),d6 + jmp $_exception_handler + +|============================================================================= +|============================================================================= +| single precision routines +|============================================================================= +|============================================================================= + +| A single precision floating point number (float) has the format: +| +| struct _float { +| unsigned int sign : 1; /* sign bit */ +| unsigned int exponent : 8; /* exponent, shifted by 126 */ +| unsigned int fraction : 23; /* fraction */ +| } float; +| +| Thus sizeof(float) = 4 (32 bits). +| +| All the routines are callable from C programs, and return the result +| in the single register d0. They also preserve all registers except +| d0-d1 and a0-a1. + +|============================================================================= +| __subsf3 +|============================================================================= + +| float __subsf3(float, float); +SYM (__subsf3): + bchg IMM (31),sp@(8) | change sign of second operand + | and fall through +|============================================================================= +| __addsf3 +|============================================================================= + +| float __addsf3(float, float); +SYM (__addsf3): +#ifndef __mcf5200__ + link a6,IMM (0) | everything will be done in registers + moveml d2-d7,sp@- | save all data registers but d0-d1 +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get first operand + movel a6@(12),d1 | get second operand + movel d0,d6 | get d0's sign bit ' + addl d0,d0 | check and clear sign bit of a + beq Laddsf$b | if zero return second operand + movel d1,d7 | save b's sign bit ' + addl d1,d1 | get rid of sign bit + beq Laddsf$a | if zero return first operand + + movel d6,a0 | save signs in address registers + movel d7,a1 | so we can use d6 and d7 + +| Get the exponents and check for denormalized and/or infinity. + + movel IMM (0x00ffffff),d4 | mask to get fraction + movel IMM (0x01000000),d5 | mask to put hidden bit back + + movel d0,d6 | save a to get exponent + andl d4,d0 | get fraction in d0 + notl d4 | make d4 into a mask for the exponent + andl d4,d6 | get exponent in d6 + beq Laddsf$a$den | branch if a is denormalized + cmpl d4,d6 | check for INFINITY or NaN + beq Laddsf$nf + swap d6 | put exponent into first word + orl d5,d0 | and put hidden bit back +Laddsf$1: +| Now we have a's exponent in d6 (second byte) and the mantissa in d0. ' + movel d1,d7 | get exponent in d7 + andl d4,d7 | + beq Laddsf$b$den | branch if b is denormalized + cmpl d4,d7 | check for INFINITY or NaN + beq Laddsf$nf + swap d7 | put exponent into first word + notl d4 | make d4 into a mask for the fraction + andl d4,d1 | get fraction in d1 + orl d5,d1 | and put hidden bit back +Laddsf$2: +| Now we have b's exponent in d7 (second byte) and the mantissa in d1. ' + +| Note that the hidden bit corresponds to bit #FLT_MANT_DIG-1, and we +| shifted right once, so bit #FLT_MANT_DIG is set (so we have one extra +| bit). + + movel d1,d2 | move b to d2, since we want to use + | two registers to do the sum + movel IMM (0),d1 | and clear the new ones + movel d1,d3 | + +| Here we shift the numbers in registers d0 and d1 so the exponents are the +| same, and put the largest exponent in d6. Note that we are using two +| registers for each number (see the discussion by D. Knuth in "Seminumerical +| Algorithms"). +#ifndef __mcf5200__ + cmpw d6,d7 | compare exponents +#else + cmpl d6,d7 | compare exponents +#endif + beq Laddsf$3 | if equal don't shift ' + bhi 5f | branch if second exponent largest +1: + subl d6,d7 | keep the largest exponent + negl d7 +#ifndef __mcf5200__ + lsrw IMM (8),d7 | put difference in lower byte +#else + lsrl IMM (8),d7 | put difference in lower byte +#endif +| if difference is too large we don't shift (actually, we can just exit) ' +#ifndef __mcf5200__ + cmpw IMM (FLT_MANT_DIG+2),d7 +#else + cmpl IMM (FLT_MANT_DIG+2),d7 +#endif + bge Laddsf$b$small +#ifndef __mcf5200__ + cmpw IMM (16),d7 | if difference >= 16 swap +#else + cmpl IMM (16),d7 | if difference >= 16 swap +#endif + bge 4f +2: +#ifndef __mcf5200__ + subw IMM (1),d7 +#else + subql IMM (1), d7 +#endif +3: +#ifndef __mcf5200__ + lsrl IMM (1),d2 | shift right second operand + roxrl IMM (1),d3 + dbra d7,3b +#else + lsrl IMM (1),d3 + btst IMM (0),d2 + beq 10f + bset IMM (31),d3 +10: lsrl IMM (1),d2 + subql IMM (1), d7 + bpl 3b +#endif + bra Laddsf$3 +4: + movew d2,d3 + swap d3 + movew d3,d2 + swap d2 +#ifndef __mcf5200__ + subw IMM (16),d7 +#else + subl IMM (16),d7 +#endif + bne 2b | if still more bits, go back to normal case + bra Laddsf$3 +5: +#ifndef __mcf5200__ + exg d6,d7 | exchange the exponents +#else + eorl d6,d7 + eorl d7,d6 + eorl d6,d7 +#endif + subl d6,d7 | keep the largest exponent + negl d7 | +#ifndef __mcf5200__ + lsrw IMM (8),d7 | put difference in lower byte +#else + lsrl IMM (8),d7 | put difference in lower byte +#endif +| if difference is too large we don't shift (and exit!) ' +#ifndef __mcf5200__ + cmpw IMM (FLT_MANT_DIG+2),d7 +#else + cmpl IMM (FLT_MANT_DIG+2),d7 +#endif + bge Laddsf$a$small +#ifndef __mcf5200__ + cmpw IMM (16),d7 | if difference >= 16 swap +#else + cmpl IMM (16),d7 | if difference >= 16 swap +#endif + bge 8f +6: +#ifndef __mcf5200__ + subw IMM (1),d7 +#else + subl IMM (1),d7 +#endif +7: +#ifndef __mcf5200__ + lsrl IMM (1),d0 | shift right first operand + roxrl IMM (1),d1 + dbra d7,7b +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 + subql IMM (1),d7 + bpl 7b +#endif + bra Laddsf$3 +8: + movew d0,d1 + swap d1 + movew d1,d0 + swap d0 +#ifndef __mcf5200__ + subw IMM (16),d7 +#else + subl IMM (16),d7 +#endif + bne 6b | if still more bits, go back to normal case + | otherwise we fall through + +| Now we have a in d0-d1, b in d2-d3, and the largest exponent in d6 (the +| signs are stored in a0 and a1). + +Laddsf$3: +| Here we have to decide whether to add or subtract the numbers +#ifndef __mcf5200__ + exg d6,a0 | get signs back + exg d7,a1 | and save the exponents +#else + movel d6,d4 + movel a0,d6 + movel d4,a0 + movel d7,d4 + movel a1,d7 + movel d4,a1 +#endif + eorl d6,d7 | combine sign bits + bmi Lsubsf$0 | if negative a and b have opposite + | sign so we actually subtract the + | numbers + +| Here we have both positive or both negative +#ifndef __mcf5200__ + exg d6,a0 | now we have the exponent in d6 +#else + movel d6,d4 + movel a0,d6 + movel d4,a0 +#endif + movel a0,d7 | and sign in d7 + andl IMM (0x80000000),d7 +| Here we do the addition. + addl d3,d1 + addxl d2,d0 +| Note: now we have d2, d3, d4 and d5 to play with! + +| Put the exponent, in the first byte, in d2, to use the "standard" rounding +| routines: + movel d6,d2 +#ifndef __mcf5200__ + lsrw IMM (8),d2 +#else + lsrl IMM (8),d2 +#endif + +| Before rounding normalize so bit #FLT_MANT_DIG is set (we will consider +| the case of denormalized numbers in the rounding routine itself). +| As in the addition (not in the subtraction!) we could have set +| one more bit we check this: + btst IMM (FLT_MANT_DIG+1),d0 + beq 1f +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 +#endif + addl IMM (1),d2 +1: + lea Laddsf$4,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Laddsf$4: +| Put back the exponent, but check for overflow. +#ifndef __mcf5200__ + cmpw IMM (0xff),d2 +#else + cmpl IMM (0xff),d2 +#endif + bhi 1f + bclr IMM (FLT_MANT_DIG-1),d0 +#ifndef __mcf5200__ + lslw IMM (7),d2 +#else + lsll IMM (7),d2 +#endif + swap d2 + orl d2,d0 + bra Laddsf$ret +1: + movew IMM (ADD),d5 + bra Lf$overflow + +Lsubsf$0: +| We are here if a > 0 and b < 0 (sign bits cleared). +| Here we do the subtraction. + movel d6,d7 | put sign in d7 + andl IMM (0x80000000),d7 + + subl d3,d1 | result in d0-d1 + subxl d2,d0 | + beq Laddsf$ret | if zero just exit + bpl 1f | if positive skip the following + bchg IMM (31),d7 | change sign bit in d7 + negl d1 + negxl d0 +1: +#ifndef __mcf5200__ + exg d2,a0 | now we have the exponent in d2 + lsrw IMM (8),d2 | put it in the first byte +#else + movel d2,d4 + movel a0,d2 + movel d4,a0 + lsrl IMM (8),d2 | put it in the first byte +#endif + +| Now d0-d1 is positive and the sign bit is in d7. + +| Note that we do not have to normalize, since in the subtraction bit +| #FLT_MANT_DIG+1 is never set, and denormalized numbers are handled by +| the rounding routines themselves. + lea Lsubsf$1,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Lsubsf$1: +| Put back the exponent (we can't have overflow!). ' + bclr IMM (FLT_MANT_DIG-1),d0 +#ifndef __mcf5200__ + lslw IMM (7),d2 +#else + lsll IMM (7),d2 +#endif + swap d2 + orl d2,d0 + bra Laddsf$ret + +| If one of the numbers was too small (difference of exponents >= +| FLT_MANT_DIG+2) we return the other (and now we don't have to ' +| check for finiteness or zero). +Laddsf$a$small: + movel a6@(12),d0 + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | restore data registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts + +Laddsf$b$small: + movel a6@(8),d0 + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | restore data registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts + +| If the numbers are denormalized remember to put exponent equal to 1. + +Laddsf$a$den: + movel d5,d6 | d5 contains 0x01000000 + swap d6 + bra Laddsf$1 + +Laddsf$b$den: + movel d5,d7 + swap d7 + notl d4 | make d4 into a mask for the fraction + | (this was not executed after the jump) + bra Laddsf$2 + +| The rest is mainly code for the different results which can be +| returned (checking always for +/-INFINITY and NaN). + +Laddsf$b: +| Return b (if a is zero). + movel a6@(12),d0 + bra 1f +Laddsf$a: +| Return a (if b is zero). + movel a6@(8),d0 +1: + movew IMM (ADD),d5 +| We have to check for NaN and +/-infty. + movel d0,d7 + andl IMM (0x80000000),d7 | put sign in d7 + bclr IMM (31),d0 | clear sign + cmpl IMM (INFINITY),d0 | check for infty or NaN + bge 2f + movel d0,d0 | check for zero (we do this because we don't ' + bne Laddsf$ret | want to return -0 by mistake + bclr IMM (31),d7 | if zero be sure to clear sign + bra Laddsf$ret | if everything OK just return +2: +| The value to be returned is either +/-infty or NaN + andl IMM (0x007fffff),d0 | check for NaN + bne Lf$inop | if mantissa not zero is NaN + bra Lf$infty + +Laddsf$ret: +| Normal exit (a and b nonzero, result is not NaN nor +/-infty). +| We have to clear the exception flags (just the exception type). + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ + orl d7,d0 | put sign bit +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | restore data registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | and return + rts + +Laddsf$ret$den: +| Return a denormalized number (for addition we don't signal underflow) ' + lsrl IMM (1),d0 | remember to shift right back once + bra Laddsf$ret | and return + +| Note: when adding two floats of the same sign if either one is +| NaN we return NaN without regard to whether the other is finite or +| not. When subtracting them (i.e., when adding two numbers of +| opposite signs) things are more complicated: if both are INFINITY +| we return NaN, if only one is INFINITY and the other is NaN we return +| NaN, but if it is finite we return INFINITY with the corresponding sign. + +Laddsf$nf: + movew IMM (ADD),d5 +| This could be faster but it is not worth the effort, since it is not +| executed very often. We sacrifice speed for clarity here. + movel a6@(8),d0 | get the numbers back (remember that we + movel a6@(12),d1 | did some processing already) + movel IMM (INFINITY),d4 | useful constant (INFINITY) + movel d0,d2 | save sign bits + movel d1,d3 + bclr IMM (31),d0 | clear sign bits + bclr IMM (31),d1 +| We know that one of them is either NaN of +/-INFINITY +| Check for NaN (if either one is NaN return NaN) + cmpl d4,d0 | check first a (d0) + bhi Lf$inop + cmpl d4,d1 | check now b (d1) + bhi Lf$inop +| Now comes the check for +/-INFINITY. We know that both are (maybe not +| finite) numbers, but we have to check if both are infinite whether we +| are adding or subtracting them. + eorl d3,d2 | to check sign bits + bmi 1f + movel d0,d7 + andl IMM (0x80000000),d7 | get (common) sign bit + bra Lf$infty +1: +| We know one (or both) are infinite, so we test for equality between the +| two numbers (if they are equal they have to be infinite both, so we +| return NaN). + cmpl d1,d0 | are both infinite? + beq Lf$inop | if so return NaN + + movel d0,d7 + andl IMM (0x80000000),d7 | get a's sign bit ' + cmpl d4,d0 | test now for infinity + beq Lf$infty | if a is INFINITY return with this sign + bchg IMM (31),d7 | else we know b is INFINITY and has + bra Lf$infty | the opposite sign + +|============================================================================= +| __mulsf3 +|============================================================================= + +| float __mulsf3(float, float); +SYM (__mulsf3): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get a into d0 + movel a6@(12),d1 | and b into d1 + movel d0,d7 | d7 will hold the sign of the product + eorl d1,d7 | + andl IMM (0x80000000),d7 + movel IMM (INFINITY),d6 | useful constant (+INFINITY) + movel d6,d5 | another (mask for fraction) + notl d5 | + movel IMM (0x00800000),d4 | this is to put hidden bit back + bclr IMM (31),d0 | get rid of a's sign bit ' + movel d0,d2 | + beq Lmulsf$a$0 | branch if a is zero + bclr IMM (31),d1 | get rid of b's sign bit ' + movel d1,d3 | + beq Lmulsf$b$0 | branch if b is zero + cmpl d6,d0 | is a big? + bhi Lmulsf$inop | if a is NaN return NaN + beq Lmulsf$inf | if a is INFINITY we have to check b + cmpl d6,d1 | now compare b with INFINITY + bhi Lmulsf$inop | is b NaN? + beq Lmulsf$overflow | is b INFINITY? +| Here we have both numbers finite and nonzero (and with no sign bit). +| Now we get the exponents into d2 and d3. + andl d6,d2 | and isolate exponent in d2 + beq Lmulsf$a$den | if exponent is zero we have a denormalized + andl d5,d0 | and isolate fraction + orl d4,d0 | and put hidden bit back + swap d2 | I like exponents in the first byte +#ifndef __mcf5200__ + lsrw IMM (7),d2 | +#else + lsrl IMM (7),d2 | +#endif +Lmulsf$1: | number + andl d6,d3 | + beq Lmulsf$b$den | + andl d5,d1 | + orl d4,d1 | + swap d3 | +#ifndef __mcf5200__ + lsrw IMM (7),d3 | +#else + lsrl IMM (7),d3 | +#endif +Lmulsf$2: | +#ifndef __mcf5200__ + addw d3,d2 | add exponents + subw IMM (F_BIAS+1),d2 | and subtract bias (plus one) +#else + addl d3,d2 | add exponents + subl IMM (F_BIAS+1),d2 | and subtract bias (plus one) +#endif + +| We are now ready to do the multiplication. The situation is as follows: +| both a and b have bit FLT_MANT_DIG-1 set (even if they were +| denormalized to start with!), which means that in the product +| bit 2*(FLT_MANT_DIG-1) (that is, bit 2*FLT_MANT_DIG-2-32 of the +| high long) is set. + +| To do the multiplication let us move the number a little bit around ... + movel d1,d6 | second operand in d6 + movel d0,d5 | first operand in d4-d5 + movel IMM (0),d4 + movel d4,d1 | the sums will go in d0-d1 + movel d4,d0 + +| now bit FLT_MANT_DIG-1 becomes bit 31: + lsll IMM (31-FLT_MANT_DIG+1),d6 + +| Start the loop (we loop #FLT_MANT_DIG times): + movew IMM (FLT_MANT_DIG-1),d3 +1: addl d1,d1 | shift sum + addxl d0,d0 + lsll IMM (1),d6 | get bit bn + bcc 2f | if not set skip sum + addl d5,d1 | add a + addxl d4,d0 +2: +#ifndef __mcf5200__ + dbf d3,1b | loop back +#else + subql IMM (1),d3 + bpl 1b +#endif + +| Now we have the product in d0-d1, with bit (FLT_MANT_DIG - 1) + FLT_MANT_DIG +| (mod 32) of d0 set. The first thing to do now is to normalize it so bit +| FLT_MANT_DIG is set (to do the rounding). +#ifndef __mcf5200__ + rorl IMM (6),d1 + swap d1 + movew d1,d3 + andw IMM (0x03ff),d3 + andw IMM (0xfd00),d1 +#else + movel d1,d3 + lsll IMM (8),d1 + addl d1,d1 + addl d1,d1 + moveq IMM (22),d5 + lsrl d5,d3 + orl d3,d1 + andl IMM (0xfffffd00),d1 +#endif + lsll IMM (8),d0 + addl d0,d0 + addl d0,d0 +#ifndef __mcf5200__ + orw d3,d0 +#else + orl d3,d0 +#endif + + movew IMM (MULTIPLY),d5 + + btst IMM (FLT_MANT_DIG+1),d0 + beq Lround$exit +#ifndef __mcf5200__ + lsrl IMM (1),d0 + roxrl IMM (1),d1 + addw IMM (1),d2 +#else + lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 + addql IMM (1),d2 +#endif + bra Lround$exit + +Lmulsf$inop: + movew IMM (MULTIPLY),d5 + bra Lf$inop + +Lmulsf$overflow: + movew IMM (MULTIPLY),d5 + bra Lf$overflow + +Lmulsf$inf: + movew IMM (MULTIPLY),d5 +| If either is NaN return NaN; else both are (maybe infinite) numbers, so +| return INFINITY with the correct sign (which is in d7). + cmpl d6,d1 | is b NaN? + bhi Lf$inop | if so return NaN + bra Lf$overflow | else return +/-INFINITY + +| If either number is zero return zero, unless the other is +/-INFINITY, +| or NaN, in which case we return NaN. +Lmulsf$b$0: +| Here d1 (==b) is zero. + movel d1,d0 | put b into d0 (just a zero) + movel a6@(8),d1 | get a again to check for non-finiteness + bra 1f +Lmulsf$a$0: + movel a6@(12),d1 | get b again to check for non-finiteness +1: bclr IMM (31),d1 | clear sign bit + cmpl IMM (INFINITY),d1 | and check for a large exponent + bge Lf$inop | if b is +/-INFINITY or NaN return NaN + lea SYM (_fpCCR),a0 | else return zero + movew IMM (0),a0@ | +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | + rts | + +| If a number is denormalized we put an exponent of 1 but do not put the +| hidden bit back into the fraction; instead we shift left until bit 23 +| (the hidden bit) is set, adjusting the exponent accordingly. We do this +| to ensure that the product of the fractions is close to 1. +Lmulsf$a$den: + movel IMM (1),d2 + andl d5,d0 +1: addl d0,d0 | shift a left (until bit 23 is set) +#ifndef __mcf5200__ + subw IMM (1),d2 | and adjust exponent +#else + subql IMM (1),d2 | and adjust exponent +#endif + btst IMM (FLT_MANT_DIG-1),d0 + bne Lmulsf$1 | + bra 1b | else loop back + +Lmulsf$b$den: + movel IMM (1),d3 + andl d5,d1 +1: addl d1,d1 | shift b left until bit 23 is set +#ifndef __mcf5200__ + subw IMM (1),d3 | and adjust exponent +#else + subl IMM (1),d3 | and adjust exponent +#endif + btst IMM (FLT_MANT_DIG-1),d1 + bne Lmulsf$2 | + bra 1b | else loop back + +|============================================================================= +| __divsf3 +|============================================================================= + +| float __divsf3(float, float); +SYM (__divsf3): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movel a6@(8),d0 | get a into d0 + movel a6@(12),d1 | and b into d1 + movel d0,d7 | d7 will hold the sign of the result + eorl d1,d7 | + andl IMM (0x80000000),d7 | + movel IMM (INFINITY),d6 | useful constant (+INFINITY) + movel d6,d5 | another (mask for fraction) + notl d5 | + movel IMM (0x00800000),d4 | this is to put hidden bit back + bclr IMM (31),d0 | get rid of a's sign bit ' + movel d0,d2 | + beq Ldivsf$a$0 | branch if a is zero + bclr IMM (31),d1 | get rid of b's sign bit ' + movel d1,d3 | + beq Ldivsf$b$0 | branch if b is zero + cmpl d6,d0 | is a big? + bhi Ldivsf$inop | if a is NaN return NaN + beq Ldivsf$inf | if a is INFINITY we have to check b + cmpl d6,d1 | now compare b with INFINITY + bhi Ldivsf$inop | if b is NaN return NaN + beq Ldivsf$underflow +| Here we have both numbers finite and nonzero (and with no sign bit). +| Now we get the exponents into d2 and d3 and normalize the numbers to +| ensure that the ratio of the fractions is close to 1. We do this by +| making sure that bit #FLT_MANT_DIG-1 (hidden bit) is set. + andl d6,d2 | and isolate exponent in d2 + beq Ldivsf$a$den | if exponent is zero we have a denormalized + andl d5,d0 | and isolate fraction + orl d4,d0 | and put hidden bit back + swap d2 | I like exponents in the first byte +#ifndef __mcf5200__ + lsrw IMM (7),d2 | +#else + lsrl IMM (7),d2 | +#endif +Ldivsf$1: | + andl d6,d3 | + beq Ldivsf$b$den | + andl d5,d1 | + orl d4,d1 | + swap d3 | +#ifndef __mcf5200__ + lsrw IMM (7),d3 | +#else + lsrl IMM (7),d3 | +#endif +Ldivsf$2: | +#ifndef __mcf5200__ + subw d3,d2 | subtract exponents + addw IMM (F_BIAS),d2 | and add bias +#else + subl d3,d2 | subtract exponents + addl IMM (F_BIAS),d2 | and add bias +#endif + +| We are now ready to do the division. We have prepared things in such a way +| that the ratio of the fractions will be less than 2 but greater than 1/2. +| At this point the registers in use are: +| d0 holds a (first operand, bit FLT_MANT_DIG=0, bit FLT_MANT_DIG-1=1) +| d1 holds b (second operand, bit FLT_MANT_DIG=1) +| d2 holds the difference of the exponents, corrected by the bias +| d7 holds the sign of the ratio +| d4, d5, d6 hold some constants + movel d7,a0 | d6-d7 will hold the ratio of the fractions + movel IMM (0),d6 | + movel d6,d7 + + movew IMM (FLT_MANT_DIG+1),d3 +1: cmpl d0,d1 | is a < b? + bhi 2f | + bset d3,d6 | set a bit in d6 + subl d1,d0 | if a >= b a <-- a-b + beq 3f | if a is zero, exit +2: addl d0,d0 | multiply a by 2 +#ifndef __mcf5200__ + dbra d3,1b +#else + subql IMM (1),d3 + bpl 1b +#endif + +| Now we keep going to set the sticky bit ... + movew IMM (FLT_MANT_DIG),d3 +1: cmpl d0,d1 + ble 2f + addl d0,d0 +#ifndef __mcf5200__ + dbra d3,1b +#else + subql IMM(1),d3 + bpl 1b +#endif + movel IMM (0),d1 + bra 3f +2: movel IMM (0),d1 +#ifndef __mcf5200__ + subw IMM (FLT_MANT_DIG),d3 + addw IMM (31),d3 +#else + subl IMM (FLT_MANT_DIG),d3 + addl IMM (31),d3 +#endif + bset d3,d1 +3: + movel d6,d0 | put the ratio in d0-d1 + movel a0,d7 | get sign back + +| Because of the normalization we did before we are guaranteed that +| d0 is smaller than 2^26 but larger than 2^24. Thus bit 26 is not set, +| bit 25 could be set, and if it is not set then bit 24 is necessarily set. + btst IMM (FLT_MANT_DIG+1),d0 + beq 1f | if it is not set, then bit 24 is set + lsrl IMM (1),d0 | +#ifndef __mcf5200__ + addw IMM (1),d2 | +#else + addl IMM (1),d2 | +#endif +1: +| Now round, check for over- and underflow, and exit. + movew IMM (DIVIDE),d5 + bra Lround$exit + +Ldivsf$inop: + movew IMM (DIVIDE),d5 + bra Lf$inop + +Ldivsf$overflow: + movew IMM (DIVIDE),d5 + bra Lf$overflow + +Ldivsf$underflow: + movew IMM (DIVIDE),d5 + bra Lf$underflow + +Ldivsf$a$0: + movew IMM (DIVIDE),d5 +| If a is zero check to see whether b is zero also. In that case return +| NaN; then check if b is NaN, and return NaN also in that case. Else +| return zero. + andl IMM (0x7fffffff),d1 | clear sign bit and test b + beq Lf$inop | if b is also zero return NaN + cmpl IMM (INFINITY),d1 | check for NaN + bhi Lf$inop | + movel IMM (0),d0 | else return zero + lea SYM (_fpCCR),a0 | + movew IMM (0),a0@ | +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | +#else + moveml sp@,d2-d7 | + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 | + rts | + +Ldivsf$b$0: + movew IMM (DIVIDE),d5 +| If we got here a is not zero. Check if a is NaN; in that case return NaN, +| else return +/-INFINITY. Remember that a is in d0 with the sign bit +| cleared already. + cmpl IMM (INFINITY),d0 | compare d0 with INFINITY + bhi Lf$inop | if larger it is NaN + bra Lf$div$0 | else signal DIVIDE_BY_ZERO + +Ldivsf$inf: + movew IMM (DIVIDE),d5 +| If a is INFINITY we have to check b + cmpl IMM (INFINITY),d1 | compare b with INFINITY + bge Lf$inop | if b is NaN or INFINITY return NaN + bra Lf$overflow | else return overflow + +| If a number is denormalized we put an exponent of 1 but do not put the +| bit back into the fraction. +Ldivsf$a$den: + movel IMM (1),d2 + andl d5,d0 +1: addl d0,d0 | shift a left until bit FLT_MANT_DIG-1 is set +#ifndef __mcf5200__ + subw IMM (1),d2 | and adjust exponent +#else + subl IMM (1),d2 | and adjust exponent +#endif + btst IMM (FLT_MANT_DIG-1),d0 + bne Ldivsf$1 + bra 1b + +Ldivsf$b$den: + movel IMM (1),d3 + andl d5,d1 +1: addl d1,d1 | shift b left until bit FLT_MANT_DIG is set +#ifndef __mcf5200__ + subw IMM (1),d3 | and adjust exponent +#else + subl IMM (1),d3 | and adjust exponent +#endif + btst IMM (FLT_MANT_DIG-1),d1 + bne Ldivsf$2 + bra 1b + +Lround$exit: +| This is a common exit point for __mulsf3 and __divsf3. + +| First check for underlow in the exponent: +#ifndef __mcf5200__ + cmpw IMM (-FLT_MANT_DIG-1),d2 +#else + cmpl IMM (-FLT_MANT_DIG-1),d2 +#endif + blt Lf$underflow +| It could happen that the exponent is less than 1, in which case the +| number is denormalized. In this case we shift right and adjust the +| exponent until it becomes 1 or the fraction is zero (in the latter case +| we signal underflow and return zero). + movel IMM (0),d6 | d6 is used temporarily +#ifndef __mcf5200__ + cmpw IMM (1),d2 | if the exponent is less than 1 we +#else + cmpl IMM (1),d2 | if the exponent is less than 1 we +#endif + bge 2f | have to shift right (denormalize) +1: +#ifndef __mcf5200__ + addw IMM (1),d2 | adjust the exponent + lsrl IMM (1),d0 | shift right once + roxrl IMM (1),d1 | + roxrl IMM (1),d6 | d6 collect bits we would lose otherwise + cmpw IMM (1),d2 | is the exponent 1 already? +#else + addql IMM (1),d2 | adjust the exponent + lsrl IMM (1),d6 + btst IMM (0),d1 + beq 11f + bset IMM (31),d6 +11: lsrl IMM (1),d1 + btst IMM (0),d0 + beq 10f + bset IMM (31),d1 +10: lsrl IMM (1),d0 + cmpl IMM (1),d2 | is the exponent 1 already? +#endif + beq 2f | if not loop back + bra 1b | + bra Lf$underflow | safety check, shouldn't execute ' +2: orl d6,d1 | this is a trick so we don't lose ' + | the extra bits which were flushed right +| Now call the rounding routine (which takes care of denormalized numbers): + lea Lround$0,a0 | to return from rounding routine + lea SYM (_fpCCR),a1 | check the rounding mode +#ifdef __mcf5200__ + clrl d6 +#endif + movew a1@(6),d6 | rounding mode in d6 + beq Lround$to$nearest +#ifndef __mcf5200__ + cmpw IMM (ROUND_TO_PLUS),d6 +#else + cmpl IMM (ROUND_TO_PLUS),d6 +#endif + bhi Lround$to$minus + blt Lround$to$zero + bra Lround$to$plus +Lround$0: +| Here we have a correctly rounded result (either normalized or denormalized). + +| Here we should have either a normalized number or a denormalized one, and +| the exponent is necessarily larger or equal to 1 (so we don't have to ' +| check again for underflow!). We have to check for overflow or for a +| denormalized number (which also signals underflow). +| Check for overflow (i.e., exponent >= 255). +#ifndef __mcf5200__ + cmpw IMM (0x00ff),d2 +#else + cmpl IMM (0x00ff),d2 +#endif + bge Lf$overflow +| Now check for a denormalized number (exponent==0). + movew d2,d2 + beq Lf$den +1: +| Put back the exponents and sign and return. +#ifndef __mcf5200__ + lslw IMM (7),d2 | exponent back to fourth byte +#else + lsll IMM (7),d2 | exponent back to fourth byte +#endif + bclr IMM (FLT_MANT_DIG-1),d0 + swap d0 | and put back exponent +#ifndef __mcf5200__ + orw d2,d0 | +#else + orl d2,d0 +#endif + swap d0 | + orl d7,d0 | and sign also + + lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +|============================================================================= +| __negsf2 +|============================================================================= + +| This is trivial and could be shorter if we didn't bother checking for NaN ' +| and +/-INFINITY. + +| float __negsf2(float); +SYM (__negsf2): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movew IMM (NEGATE),d5 + movel a6@(8),d0 | get number to negate in d0 + bchg IMM (31),d0 | negate + movel d0,d1 | make a positive copy + bclr IMM (31),d1 | + tstl d1 | check for zero + beq 2f | if zero (either sign) return +zero + cmpl IMM (INFINITY),d1 | compare to +INFINITY + blt 1f | + bhi Lf$inop | if larger (fraction not zero) is NaN + movel d0,d7 | else get sign and return INFINITY + andl IMM (0x80000000),d7 + bra Lf$infty +1: lea SYM (_fpCCR),a0 + movew IMM (0),a0@ +#ifndef __mcf5200__ + moveml sp@+,d2-d7 +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts +2: bclr IMM (31),d0 + bra 1b + +|============================================================================= +| __cmpsf2 +|============================================================================= + +GREATER = 1 +LESS = -1 +EQUAL = 0 + +| int __cmpsf2(float, float); +SYM (__cmpsf2): +#ifndef __mcf5200__ + link a6,IMM (0) + moveml d2-d7,sp@- | save registers +#else + link a6,IMM (-24) + moveml d2-d7,sp@ +#endif + movew IMM (COMPARE),d5 + movel a6@(8),d0 | get first operand + movel a6@(12),d1 | get second operand +| Check if either is NaN, and in that case return garbage and signal +| INVALID_OPERATION. Check also if either is zero, and clear the signs +| if necessary. + movel d0,d6 + andl IMM (0x7fffffff),d0 + beq Lcmpsf$a$0 + cmpl IMM (0x7f800000),d0 + bhi Lf$inop +Lcmpsf$1: + movel d1,d7 + andl IMM (0x7fffffff),d1 + beq Lcmpsf$b$0 + cmpl IMM (0x7f800000),d1 + bhi Lf$inop +Lcmpsf$2: +| Check the signs + eorl d6,d7 + bpl 1f +| If the signs are not equal check if a >= 0 + tstl d6 + bpl Lcmpsf$a$gt$b | if (a >= 0 && b < 0) => a > b + bmi Lcmpsf$b$gt$a | if (a < 0 && b >= 0) => a < b +1: +| If the signs are equal check for < 0 + tstl d6 + bpl 1f +| If both are negative exchange them +#ifndef __mcf5200__ + exg d0,d1 +#else + movel d0,d7 + movel d1,d0 + movel d7,d1 +#endif +1: +| Now that they are positive we just compare them as longs (does this also +| work for denormalized numbers?). + cmpl d0,d1 + bhi Lcmpsf$b$gt$a | |b| > |a| + bne Lcmpsf$a$gt$b | |b| < |a| +| If we got here a == b. + movel IMM (EQUAL),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 +#endif + unlk a6 + rts +Lcmpsf$a$gt$b: + movel IMM (GREATER),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts +Lcmpsf$b$gt$a: + movel IMM (LESS),d0 +#ifndef __mcf5200__ + moveml sp@+,d2-d7 | put back the registers +#else + moveml sp@,d2-d7 + | XXX if frame pointer is ever removed, stack pointer must + | be adjusted here. +#endif + unlk a6 + rts + +Lcmpsf$a$0: + bclr IMM (31),d6 + bra Lcmpsf$1 +Lcmpsf$b$0: + bclr IMM (31),d7 + bra Lcmpsf$2 + +|============================================================================= +| rounding routines +|============================================================================= + +| The rounding routines expect the number to be normalized in registers +| d0-d1, with the exponent in register d2. They assume that the +| exponent is larger or equal to 1. They return a properly normalized number +| if possible, and a denormalized number otherwise. The exponent is returned +| in d2. + +Lround$to$nearest: +| We now normalize as suggested by D. Knuth ("Seminumerical Algorithms"): +| Here we assume that the exponent is not too small (this should be checked +| before entering the rounding routine), but the number could be denormalized. + +| Check for denormalized numbers: +1: btst IMM (FLT_MANT_DIG),d0 + bne 2f | if set the number is normalized +| Normalize shifting left until bit #FLT_MANT_DIG is set or the exponent +| is one (remember that a denormalized number corresponds to an +| exponent of -F_BIAS+1). +#ifndef __mcf5200__ + cmpw IMM (1),d2 | remember that the exponent is at least one +#else + cmpl IMM (1),d2 | remember that the exponent is at least one +#endif + beq 2f | an exponent of one means denormalized + addl d1,d1 | else shift and adjust the exponent + addxl d0,d0 | +#ifndef __mcf5200__ + dbra d2,1b | +#else + subql IMM (1),d2 + bpl 1b +#endif +2: +| Now round: we do it as follows: after the shifting we can write the +| fraction part as f + delta, where 1 < f < 2^25, and 0 <= delta <= 2. +| If delta < 1, do nothing. If delta > 1, add 1 to f. +| If delta == 1, we make sure the rounded number will be even (odd?) +| (after shifting). + btst IMM (0),d0 | is delta < 1? + beq 2f | if so, do not do anything + tstl d1 | is delta == 1? + bne 1f | if so round to even + movel d0,d1 | + andl IMM (2),d1 | bit 1 is the last significant bit + addl d1,d0 | + bra 2f | +1: movel IMM (1),d1 | else add 1 + addl d1,d0 | +| Shift right once (because we used bit #FLT_MANT_DIG!). +2: lsrl IMM (1),d0 +| Now check again bit #FLT_MANT_DIG (rounding could have produced a +| 'fraction overflow' ...). + btst IMM (FLT_MANT_DIG),d0 + beq 1f + lsrl IMM (1),d0 +#ifndef __mcf5200__ + addw IMM (1),d2 +#else + addql IMM (1),d2 +#endif +1: +| If bit #FLT_MANT_DIG-1 is clear we have a denormalized number, so we +| have to put the exponent to zero and return a denormalized number. + btst IMM (FLT_MANT_DIG-1),d0 + beq 1f + jmp a0@ +1: movel IMM (0),d2 + jmp a0@ + +Lround$to$zero: +Lround$to$plus: +Lround$to$minus: + jmp a0@ +#endif /* L_float */ + +| gcc expects the routines __eqdf2, __nedf2, __gtdf2, __gedf2, +| __ledf2, __ltdf2 to all return the same value as a direct call to +| __cmpdf2 would. In this implementation, each of these routines +| simply calls __cmpdf2. It would be more efficient to give the +| __cmpdf2 routine several names, but separating them out will make it +| easier to write efficient versions of these routines someday. + +#ifdef L_eqdf2 + .text + .proc + .globl SYM (__eqdf2) +SYM (__eqdf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_eqdf2 */ + +#ifdef L_nedf2 + .text + .proc + .globl SYM (__nedf2) +SYM (__nedf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_nedf2 */ + +#ifdef L_gtdf2 + .text + .proc + .globl SYM (__gtdf2) +SYM (__gtdf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_gtdf2 */ + +#ifdef L_gedf2 + .text + .proc + .globl SYM (__gedf2) +SYM (__gedf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_gedf2 */ + +#ifdef L_ltdf2 + .text + .proc + .globl SYM (__ltdf2) +SYM (__ltdf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_ltdf2 */ + +#ifdef L_ledf2 + .text + .proc + .globl SYM (__ledf2) +SYM (__ledf2): + link a6,IMM (0) + movl a6@(20),sp@- + movl a6@(16),sp@- + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpdf2) + unlk a6 + rts +#endif /* L_ledf2 */ + +| The comments above about __eqdf2, et. al., also apply to __eqsf2, +| et. al., except that the latter call __cmpsf2 rather than __cmpdf2. + +#ifdef L_eqsf2 + .text + .proc + .globl SYM (__eqsf2) +SYM (__eqsf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_eqsf2 */ + +#ifdef L_nesf2 + .text + .proc + .globl SYM (__nesf2) +SYM (__nesf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_nesf2 */ + +#ifdef L_gtsf2 + .text + .proc + .globl SYM (__gtsf2) +SYM (__gtsf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_gtsf2 */ + +#ifdef L_gesf2 + .text + .proc + .globl SYM (__gesf2) +SYM (__gesf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_gesf2 */ + +#ifdef L_ltsf2 + .text + .proc + .globl SYM (__ltsf2) +SYM (__ltsf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_ltsf2 */ + +#ifdef L_lesf2 + .text + .proc + .globl SYM (__lesf2) +SYM (__lesf2): + link a6,IMM (0) + movl a6@(12),sp@- + movl a6@(8),sp@- + jbsr SYM (__cmpsf2) + unlk a6 + rts +#endif /* L_lesf2 */ diff --git a/gcc/config/m68k/lb1sun3.asm b/gcc/config/m68k/lb1sun3.asm new file mode 100755 index 0000000..7b1854c --- /dev/null +++ b/gcc/config/m68k/lb1sun3.asm @@ -0,0 +1,1036 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware, + calling the Sun3 floating point support routines. */ +/* Copyright (C) 1992 Free Software Foundation, Inc. + +This file 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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 this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifdef L_mulsi3 + .text + .proc + .globl SYM (__mulsi3) +SYM (__mulsi3): + movew sp@(4), d0 /* x0 -> d0 */ + muluw sp@(10), d0 /* x0*y1 */ + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(8), d1 /* x1*y0 */ + addw d1, d0 + swap d0 + clrw d0 + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(10), d1 /* x1*y1 */ + addl d1, d0 + + rts +#endif /* L_mulsi3 */ + +#ifdef L_udivsi3 + .text + .proc + .globl SYM (__udivsi3) +SYM (__udivsi3): + movel d2, sp@- + movel sp@(12), d1 /* d1 = divisor */ + movel sp@(8), d0 /* d0 = dividend */ + + cmpl #0x10000, d1 /* divisor >= 2 ^ 16 ? */ + jcc L3 /* then try next algorithm */ + movel d0, d2 + clrw d2 + swap d2 + divu d1, d2 /* high quotient in lower word */ + movew d2, d0 /* save high quotient */ + swap d0 + movew sp@(10), d2 /* get low dividend + high rest */ + divu d1, d2 /* low quotient */ + movew d2, d0 + jra L6 + +L3: movel d1, d2 /* use d2 as divisor backup */ +L4: lsrl #1, d1 /* shift divisor */ + lsrl #1, d0 /* shift dividend */ + cmpl #0x10000, d1 /* still divisor >= 2 ^ 16 ? */ + jcc L4 + divu d1, d0 /* now we have 16 bit divisor */ + andl #0xffff, d0 /* mask out divisor, ignore remainder */ + +/* Muliply the 16 bit tentative quotient with the 32 bit divisor. Because of + the operand ranges, this might give a 33 bit product. If this product is + greater than the dividend, the tentative quotient was too large. */ + movel d2, d1 + mulu d0, d1 /* low part, 32 bits */ + swap d2 + mulu d0, d2 /* high part, at most 17 bits */ + swap d2 /* align high part with low part */ + btst #0, d2 /* high part 17 bits? */ + jne L5 /* if 17 bits, quotient was too large */ + addl d2, d1 /* add parts */ + jcs L5 /* if sum is 33 bits, quotient was too large */ + cmpl sp@(8), d1 /* compare the sum with the dividend */ + jls L6 /* if sum > dividend, quotient was too large */ +L5: subql #1, d0 /* adjust quotient */ + +L6: movel sp@+, d2 + rts +#endif /* L_udivsi3 */ + +#ifdef L_divsi3 + .text + .proc + .globl SYM (__divsi3) +SYM (__divsi3): + movel d2, sp@- + + moveb #1, d2 /* sign of result stored in d2 (=1 or =-1) */ + movel sp@(12), d1 /* d1 = divisor */ + jpl L1 + negl d1 + negb d2 /* change sign because divisor <0 */ +L1: movel sp@(8), d0 /* d0 = dividend */ + jpl L2 + negl d0 + negb d2 + +L2: movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */ + addql #8, sp + + tstb d2 + jpl L3 + negl d0 + +L3: movel sp@+, d2 + rts +#endif /* L_divsi3 */ + +#ifdef L_umodsi3 + .text + .proc + .globl SYM (__umodsi3) +SYM (__umodsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) + addql #8, sp + movel sp@(8), d1 /* d1 = divisor */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql #8, sp + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts +#endif /* L_umodsi3 */ + +#ifdef L_modsi3 + .text + .proc + .globl SYM (__modsi3) +SYM (__modsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__divsi3) + addql #8, sp + movel sp@(8), d1 /* d1 = divisor */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql #8, sp + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts +#endif /* L_modsi3 */ + + +#ifdef L_divdf3 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___divdf3 +___divdf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + lea a6@(16),a0 + jbsr Fdivd + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_divdf3 */ + +#ifdef L_muldf3 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___muldf3 +___muldf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + lea a6@(16),a0 + jbsr Fmuld + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_muldf3 */ + +#ifdef L_negdf2 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___negdf2 +___negdf2: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),a6@(-4) + bchg #31,d0 + movl d0,a6@(-8) + movl a6@(-4),d1 +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_negdf2 */ + +#ifdef L_adddf3 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___adddf3 +___adddf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + lea a6@(16),a0 + jbsr Faddd + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_adddf3 */ + +#ifdef L_subdf3 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___subdf3 +___subdf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + lea a6@(16),a0 + jbsr Fsubd + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_subdf3 */ + +#ifdef L_fixdfsi +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 4 + LS17 = 128 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___fixdfsi +___fixdfsi: +|#PROLOGUE# 0 + link a6,#-4 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fintd +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_fixdfsi */ + +#ifdef L_fixsfsi +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 4 + LS17 = 128 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___fixsfsi +___fixsfsi: +|#PROLOGUE# 0 + link a6,#-4 +|#PROLOGUE# 1 + movl a6@(8),d0 + jbsr Fints +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_fixsfsi */ + +#ifdef L_floatsidf +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___floatsidf +___floatsidf: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + jbsr Ffltd + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_floatsidf */ + +#ifdef L_floatsisf +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___floatsisf +___floatsisf: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + jbsr Fflts + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_floatsisf */ + +#ifdef L_truncdfsf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___truncdfsf2 +___truncdfsf2: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fdtos + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_truncdfsf2 */ + +#ifdef L_extendsfdf2 +LL0: + .data + .data + .text + .proc +|#PROC# 07 + LF17 = 8 + LS17 = 0 + LFF17 = 8 + LSS17 = 0 + LV17 = 8 + .text + .globl ___extendsfdf2 +___extendsfdf2: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + jbsr Fstod + movl d0,a6@(-8) + movl d1,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_extendsfdf2 */ + +#ifdef L_addsf3 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___addsf3 +___addsf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fadds + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_addsf3 */ + +#ifdef L_negsf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___negsf2 +___negsf2: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + bchg #31,d0 + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_negsf2 */ + +#ifdef L_subsf3 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___subsf3 +___subsf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fsubs + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_subsf3 */ + +#ifdef L_mulsf3 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___mulsf3 +___mulsf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fmuls + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_mulsf3 */ + +#ifdef L_divsf3 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 128 + LFF17 = 4 + LSS17 = 0 + LV17 = 4 + .text + .globl ___divsf3 +___divsf3: +|#PROLOGUE# 0 + link a6,#-8 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + jbsr Fdivs + movl d0,a6@(-4) +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_divsf3 */ + +#ifdef L_eqdf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 4 + LS17 = 128 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___eqdf2 +___eqdf2: +|#PROLOGUE# 0 + link a6,#-4 +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + lea a6@(16),a0 + jbsr Fcmpd + jfeq L77003 + moveq #1,d0 + jra L77005 +L77003: + moveq #0,d0 +L77005: +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_eqdf2 */ + +#ifdef L_nedf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___nedf2 +___nedf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + moveq #0,d7 + lea a6@(16),a0 + jbsr Fcmpd + sfneq d7 + negb d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_nedf2 */ + +#ifdef L_gtdf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___gtdf2 +___gtdf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + moveq #0,d7 + lea a6@(16),a0 + jbsr Fcmpd + sfgt d7 + negb d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_gtdf2 */ + +#ifdef L_gedf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___gedf2 +___gedf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + moveq #0,d7 + lea a6@(16),a0 + jbsr Fcmpd + sfge d7 + negb d7 + subql #1,d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_gedf2 */ + +#ifdef L_ltdf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___ltdf2 +___ltdf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + moveq #0,d7 + lea a6@(16),a0 + jbsr Fcmpd + sflt d7 + negb d7 + negl d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_ltdf2 */ + +#ifdef L_ledf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___ledf2 +___ledf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d2,sp@ +|#PROLOGUE# 1 + movl a6@(8),d0 + movl a6@(12),d1 + moveq #0,d2 + lea a6@(16),a0 + jbsr Fcmpd + sfle d2 + negb d2 + moveq #1,d0 + subl d2,d0 +|#PROLOGUE# 2 + movl a6@(-8),d2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_ledf2 */ + +#ifdef L_eqsf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 4 + LS17 = 128 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___eqsf2 +___eqsf2: +|#PROLOGUE# 0 + link a6,#-4 +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + jbsr Fcmps + jfeq L77003 + moveq #1,d0 + jra L77005 +L77003: + moveq #0,d0 +L77005: +|#PROLOGUE# 2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_eqsf2 */ + +#ifdef L_nesf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___nesf2 +___nesf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + moveq #0,d7 + jbsr Fcmps + sfneq d7 + negb d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_nesf2 */ + +#ifdef L_gtsf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___gtsf2 +___gtsf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + moveq #0,d7 + jbsr Fcmps + sfgt d7 + negb d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_gtsf2 */ + +#ifdef L_gesf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___gesf2 +___gesf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + moveq #0,d7 + jbsr Fcmps + sfge d7 + negb d7 + subql #1,d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_gesf2 */ + +#ifdef L_ltsf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___ltsf2 +___ltsf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d7,sp@ +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + moveq #0,d7 + jbsr Fcmps + sflt d7 + negb d7 + negl d7 + movl d7,d0 +|#PROLOGUE# 2 + movl a6@(-8),d7 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_ltsf2 */ + +#ifdef L_lesf2 +LL0: + .data + .data + .text + .proc +|#PROC# 04 + LF17 = 8 + LS17 = 132 + LFF17 = 0 + LSS17 = 0 + LV17 = 0 + .text + .globl ___lesf2 +___lesf2: +|#PROLOGUE# 0 + link a6,#-8 + movl d2,sp@ +|#PROLOGUE# 1 + movl a6@(12),d1 + movl a6@(8),d0 + moveq #0,d2 + jbsr Fcmps + sfle d2 + negb d2 + moveq #1,d0 + subl d2,d0 +|#PROLOGUE# 2 + movl a6@(-8),d2 + unlk a6 +|#PROLOGUE# 3 + rts +#endif /* L_lesf2 */ + diff --git a/gcc/config/m68k/linux-aout.h b/gcc/config/m68k/linux-aout.h new file mode 100755 index 0000000..692725e --- /dev/null +++ b/gcc/config/m68k/linux-aout.h @@ -0,0 +1,77 @@ +/* Definitions for Motorola m68k running Linux-based GNU systems. + Copyright (C) 1995, 1996, 1997 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 1, 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 <m68k/m68k.h> +#include <linux-aout.h> + +/* 68020 with 68881 */ +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +#define DBX_DEBUGGING_INFO + +#define ASM_COMMENT_START "|" + +#define CPP_PREDEFINES \ + "-Dunix -Dmc68000 -Dmc68020 -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(m68k) -Amachine(m68k)" + +#undef CPP_SPEC +#if TARGET_DEFAULT & MASK_68881 +#define CPP_SPEC \ + "%{!msoft-float:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE}" +#else +#define CPP_SPEC \ + "%{m68881:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE}" +#endif + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES {"ieee-fp", 0}, + +#undef ASM_SPEC +#define ASM_SPEC \ + "%{m68030} %{m68040} %{fpic:-k} %{fPIC:-k}" + +#undef LIB_SPEC +#if 1 +/* We no longer link with libc_p.a or libg.a by default. If you want + to profile or debug the GNU/Linux C library, please add -lc_p or -ggdb + to LDFLAGS at the link time, respectively. */ +#define LIB_SPEC \ + "%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}" +#else +#define LIB_SPEC \ + "%{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}" +#endif + +/* We want to pass -v to linker */ +#undef LINK_SPEC +#define LINK_SPEC "-m m68klinux %{v:-dll-verbose}" + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* Don't default to pcc-struct-return, because gcc is the only compiler. */ +#undef PCC_STATIC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Allow folding division by zero. */ +#define REAL_INFINITY diff --git a/gcc/config/m68k/linux.h b/gcc/config/m68k/linux.h new file mode 100755 index 0000000..0df0bd8 --- /dev/null +++ b/gcc/config/m68k/linux.h @@ -0,0 +1,387 @@ +/* Definitions for Motorola 68k running Linux-based GNU systems with + ELF format. + Copyright (C) 1995, 1996, 1997 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 1, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define LINUX_DEFAULT_ELF +#define MOTOROLA /* Use Motorola syntax */ +#define USE_GAS /* But GAS wants jbsr instead of jsr */ + +#include <m68k/m68k.h> + +/* Make sure CC1 is undefined. */ +#undef CC1_SPEC + +#include <linux.h> /* some common stuff */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k GNU/Linux with ELF)"); + +/* 68020 with 68881 */ +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +/* for 68k machines this only needs to be TRUE for the 68000 */ + +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES {"ieee-fp", 0}, + +/* Here are four prefixes that are used by asm_fprintf to + facilitate customization for alternate assembler syntaxes. + Machines with no likelihood of an alternate syntax need not + define these and need not use asm_fprintf. */ + +/* The prefix for register names. Note that REGISTER_NAMES + is supposed to include this prefix. Also note that this is NOT an + fprintf format string, it is a literal string */ + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +/* The prefix for local (compiler generated) labels. + These labels will not appear in the symbol table. */ + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +#define ASM_COMMENT_START "|" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number. + Motorola format uses different register names than defined in m68k.h. */ + +#undef REGISTER_NAMES + +#ifndef SUPPORT_SUN_FPA + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7" } + +#else /* SUPPORTED_SUN_FPA */ + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6", "%fpa7", \ + "%fpa8", "%fpa9", "%fpa10","%fpa11","%fpa12","%fpa13","%fpa14","%fpa15", \ + "%fpa16","%fpa17","%fpa18","%fpa19","%fpa20","%fpa21","%fpa22","%fpa23", \ + "%fpa24","%fpa25","%fpa26","%fpa27","%fpa28","%fpa29","%fpa30","%fpa31" } + +#endif /* defined SUPPORT_SUN_FPA */ + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +#define CPP_PREDEFINES \ + "-D__ELF__ -Dunix -Dmc68000 -Dmc68020 -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(m68k) -Amachine(m68k)" + +#undef CPP_SPEC +#ifdef USE_GNULIBC_1 +#if TARGET_DEFAULT & MASK_68881 +#define CPP_SPEC \ + "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!msoft-float:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE}" +#else +#define CPP_SPEC \ + "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m68881:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE}" +#endif +#else +#if TARGET_DEFAULT & MASK_68881 +#define CPP_SPEC \ + "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!msoft-float:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" +#else +#define CPP_SPEC \ + "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m68881:-D__HAVE_68881__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" +#endif +#endif + +/* We override the ASM_SPEC from svr4.h because we must pass -m68040 down + to the assembler. */ +#undef ASM_SPEC +#define ASM_SPEC \ + "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \ +%{m68040} %{m68060:-m68040}" + +/* Provide a LINK_SPEC appropriate for GNU/Linux. Here we provide support + for the special GCC options -static and -shared, which allow us to + link things in one of these three modes by applying the appropriate + combinations of options at link-time. We like to support here for + as many of the other GNU linker options as possible. But I don't + have the time to search for those flags. I am sure how to add + support for -soname shared_object_name. H.J. + + I took out %{v:%{!V:-V}}. It is too much :-(. They can use + -Wl,-V. + + When the -shared link option is used a final link is not being + done. */ + +/* If ELF is the default format, we should not use /lib/elf. */ + +#undef LINK_SPEC +#ifdef USE_GNULIBC_1 +#ifndef LINUX_DEFAULT_ELF +#define LINK_SPEC "-m m68kelf %{shared} %{symbolic:-shared -Bsymbolic} \ + %{!shared:%{!symbolic: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker*:-dynamic-linker /lib/elf/ld-linux.so.1} \ + %{!rpath*:-rpath /lib/elf/}} %{static}}}" +#else +#define LINK_SPEC "-m m68kelf %{shared} %{symbolic:-shared -Bsymbolic} \ + %{!shared:%{!symbolic: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker*:-dynamic-linker /lib/ld-linux.so.1}} \ + %{static}}}" +#endif +#else +#define LINK_SPEC "-m m68kelf %{shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker*:-dynamic-linker /lib/ld.so.1}} \ + %{static}}" +#endif + +/* For compatibility with linux/a.out */ + +#undef PCC_BITFIELD_TYPE_MATTERS + +/* Currently, JUMP_TABLES_IN_TEXT_SECTION must be defined in order to + keep switch tables in the text section. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Use the default action for outputting the case label. */ +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp %%pc@(2,%0:l)"; \ + else \ + return "jmp %%pc@(2,%0:w)"; \ + } while (0) + +/* This is how to output an assembler line that says to advance the + location counter to a multiple of 2**LOG bytes. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) > 0) \ + fprintf ((FILE), "\t%s \t%u\n", ALIGN_ASM_OP, 1 << (LOG)); + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as uninitialized global + data. */ + +#define BSS_SECTION_ASM_OP ".section\t.bss" + +/* A C statement (sans semicolon) to output to the stdio stream + FILE the assembler definition of uninitialized global DECL named + NAME whose size is SIZE bytes and alignment is ALIGN bytes. + Try to use asm_output_aligned_bss to implement this macro. */ + +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + asm_fprintf (FILE, "\tlea (%LLP%d,%Rpc),%Ra1\n", (LABELNO)); \ + if (flag_pic) \ + fprintf (FILE, "\tbsr.l _mcount@PLTPC\n"); \ + else \ + fprintf (FILE, "\tjbsr _mcount\n"); \ +} + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* Allow folding division by zero. */ +#define REAL_INFINITY + +/* 1 if N is a possible register number for a function value. For + m68k/SVR4 allow d0, a0, or fp0 as return registers, for integral, + pointer, or floating types, respectively. Reject fp0 if not using + a 68881 coprocessor. */ + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (N) == 8 || (TARGET_68881 && (N) == 16)) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 + +/* Define how to generate (in the callee) the output value of a + function and how to find (in the caller) the value returned by a + function. VALTYPE is the data type of the value (as a tree). If + the precise function being called is known, FUNC is its + FUNCTION_DECL; otherwise, FUNC is 0. For m68k/SVR4 generate the + result in d0, a0, or fp0 as appropriate. */ + +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_68881 \ + ? gen_rtx_REG (TYPE_MODE (VALTYPE), 16) \ + : (POINTER_TYPE_P (VALTYPE) \ + ? gen_rtx_REG (TYPE_MODE (VALTYPE), 8) \ + : gen_rtx_REG (TYPE_MODE (VALTYPE), 0))) + +/* For compatibility with the large body of existing code which does + not always properly declare external functions returning pointer + types, the m68k/SVR4 convention is to copy the value returned for + pointer functions from a0 to d0 in the function epilogue, so that + callers that have neglected to properly declare the callee can + still find the correct return value. */ + +extern int current_function_returns_pointer; +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +do { \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\tmove.l %Ra0,%Rd0\n"); \ +} while (0); + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. + For m68k/SVR4 look for integer values in d0, pointer values in d0 + (returned in both d0 and a0), and floating values in fp0. */ + +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + ((((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode) \ + && TARGET_68881) \ + ? gen_rtx_REG (MODE, 16) \ + : gen_rtx_REG (MODE, 0)) + +/* In m68k svr4, a symbol_ref rtx can be a valid PIC operand if it is + an operand of a function call. */ +#undef LEGITIMATE_PIC_OPERAND_P +#define LEGITIMATE_PIC_OPERAND_P(X) \ + ((! symbolic_operand (X, VOIDmode) \ + && ! (GET_CODE (X) == CONST_DOUBLE && CONST_DOUBLE_MEM (X) \ + && GET_CODE (CONST_DOUBLE_MEM (X)) == MEM \ + && symbolic_operand (XEXP (CONST_DOUBLE_MEM (X), 0), VOIDmode))) \ + || (GET_CODE (X) == SYMBOL_REF && SYMBOL_REF_FLAG (X))) + +/* Turn off function cse if we are doing PIC. We always want function + call to be done as `bsr foo@PLTPC', so it will force the assembler + to create the PLT entry for `foo'. Doing function cse will cause + the address of `foo' to be loaded into a register, which is exactly + what we want to avoid when we are doing PIC on svr4 m68k. */ +#undef SUBTARGET_OVERRIDE_OPTIONS +#define SUBTARGET_OVERRIDE_OPTIONS \ + if (flag_pic) flag_no_function_cse = 1; + +/* For m68k SVR4, structures are returned using the reentrant + technique. */ +#undef PCC_STATIC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Finalize the trampoline by flushing the insn cache. */ + +#undef FINALIZE_TRAMPOLINE +#define FINALIZE_TRAMPOLINE(TRAMP) \ + emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \ + 0, VOIDmode, 2, TRAMP, Pmode, \ + plus_constant (TRAMP, TRAMPOLINE_SIZE), Pmode); + +/* Clear the instruction cache from `beg' to `end'. This makes an + inline system call to SYS_cacheflush. The arguments are as + follows: + + cacheflush (addr, scope, cache, len) + + addr - the start address for the flush + scope - the scope of the flush (see the cpush insn) + cache - which cache to flush (see the cpush insn) + len - a factor relating to the number of flushes to perform: + len/16 lines, or len/4096 pages. */ + +#define CLEAR_INSN_CACHE(BEG, END) \ +{ \ + register unsigned long _beg __asm ("%d1") = (unsigned long) (BEG); \ + unsigned long _end = (unsigned long) (END); \ + register unsigned long _len __asm ("%d4") = (_end - _beg + 32); \ + __asm __volatile \ + ("move%.l %#123, %/d0\n\t" /* system call nr */ \ + "move%.l %#1, %/d2\n\t" /* clear lines */ \ + "move%.l %#3, %/d3\n\t" /* insn+data caches */ \ + "trap %#0" \ + : /* no outputs */ \ + : "d" (_beg), "d" (_len) \ + : "%d0", "%d2", "%d3"); \ +} + +/* Output code to add DELTA to the first argument, and then jump to FUNCTION. + Used for C++ multiple inheritance. */ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + if (DELTA > 0 && DELTA <= 8) \ + asm_fprintf (FILE, "\taddq.l %I%d,4(%Rsp)\n", DELTA); \ + else if (DELTA < 0 && DELTA >= -8) \ + asm_fprintf (FILE, "\tsubq.l %I%d,4(%Rsp)\n", -DELTA); \ + else \ + asm_fprintf (FILE, "\tadd.l %I%d,4(%Rsp)\n", DELTA); \ + \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tbra.l "); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "@PLTPC\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tjmp "); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "\n"); \ + } \ +} while (0) diff --git a/gcc/config/m68k/lynx-ng.h b/gcc/config/m68k/lynx-ng.h new file mode 100755 index 0000000..ac3afac --- /dev/null +++ b/gcc/config/m68k/lynx-ng.h @@ -0,0 +1,43 @@ +/* Definitions for Motorola 680x0 running LynxOS, using Lynx's old as and ld. + Copyright (C) 1993, 1995, 1996 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 <m68k/m68k.h> +#include <m68k/coff.h> +#include <lynx-ng.h> + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* Names to predefine in the preprocessor for this target machine. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Dmc68000 -DM68K -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(m68k) -Amachine(m68k)" + +/* Provide required defaults for linker switches. */ + +#undef LINK_SPEC +#define LINK_SPEC "-P1000 %{msystem-v:-V} %{mcoff:-k}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 diff --git a/gcc/config/m68k/lynx.h b/gcc/config/m68k/lynx.h new file mode 100755 index 0000000..8c54b8b --- /dev/null +++ b/gcc/config/m68k/lynx.h @@ -0,0 +1,74 @@ +/* Definitions for Motorola 680x0 running LynxOS. + Copyright (C) 1993, 1994, 1995, 1996 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 <m68k/m68k.h> +#include <m68k/coff.h> + +#undef CTORS_SECTION_ASM_OP +#undef DTORS_SECTION_ASM_OP +#undef ASM_OUTPUT_DESTRUCTOR +#undef SELECT_RTX_SECTION + +#define BSS_SECTION_ASM_OP ".bss" + +#define ASM_LONG ".long" + +#include <lynx.h> + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* Names to predefine in the preprocessor for this target machine. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Dmc68000 -DM68K -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(m68k) -Amachine(m68k)" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Lynx uses d2 and d3 as scratch registers. */ +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0 } + +/* Return floating point values in a fp register. This make fp code a + little bit faster. It also makes -msoft-float code incompatible with + -m68881 code, so people have to be careful not to mix the two. */ +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), \ + ((TARGET_68881 \ + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode)) \ + ? 16 : 0)) + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (TARGET_68881 && (N) == 16)) + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 diff --git a/gcc/config/m68k/m68020-elf.h b/gcc/config/m68k/m68020-elf.h new file mode 100755 index 0000000..94b5d44 --- /dev/null +++ b/gcc/config/m68k/m68020-elf.h @@ -0,0 +1,53 @@ +/* Definitions of target machine for GNU compiler. "naked" 68020, + elf object files and debugging, version. + Copyright (C) 1987, 1988, 1992, 1995, 1996 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. */ + +/* This comment is here to see if it will keep Sun's cpp from dying. */ + +#include "m68k/m68k-none.h" +#include "m68k/m68kelf.h" +#include "elfos.h" +/* m68k/m68kemb.h sets some macros in ways that override the svr4 abi. */ +#include "m68k/m68kemb.h" + +/* We need to override the default specs from elfos.h. This suppresses the + loading of crt0.o by gcc's default linker spec. For embedded targets crt0 + now comes from the linker script. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s" + +#define LIB_SPEC "-lc" + +/* ??? Quick hack to get constructors working. Make this look more like a + COFF target, so the existing dejagnu/libgloss support works. A better + solution would be to make the necessary dejagnu and libgloss changes so + that we can use normal the ELF constructor mechanism. */ +#undef INIT_SECTION_ASM_OP +#undef FINI_SECTION_ASM_OP +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "" + +/* end of m68020-elf.h */ diff --git a/gcc/config/m68k/m68360-coff.h b/gcc/config/m68k/m68360-coff.h new file mode 100755 index 0000000..9f0c718 --- /dev/null +++ b/gcc/config/m68k/m68360-coff.h @@ -0,0 +1,27 @@ +/* Definitions of target machine for GNU compiler. "naked" 68360, + COFF object files and debugging, version. + Copyright (C) 1987, 1988, 1991, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define MOTOROLA /* Use Motorola syntax rather than MIT. */ + +#include "m68k/m68360-none.h" +#include "m68k/m68kemb.h" +#include "m68k/coff.h" + +/* end of m68360-coff.h */ diff --git a/gcc/config/m68k/m68360-none.h b/gcc/config/m68k/m68360-none.h new file mode 100755 index 0000000..27b1d60 --- /dev/null +++ b/gcc/config/m68k/m68360-none.h @@ -0,0 +1,129 @@ +/* Definitions of target machine for GNU compiler. "naked" 68360. + Copyright (C) 1987, 1988, 1992, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "m68k/m68k.h" + +/* See m68k.h. 1 means 68020 without bitfield insns or 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT 1 +#endif + +/* Names to predefine in the preprocessor for this target machine. + Always define mc68000. Other definitions depend on switches given + to the compiler: + + -m68000: define nothing else + -m68020, -mc68020: define mc68020 + -m68030: define mc68030 + -m68040: define mc68040 + -m68020-40: define mc68020 mc68030 mc68040 + -m68302: define mc68302 + -m68332: define mc68332 + default, -m68360: define mc68360 + */ + +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000" +#endif + +#ifndef CPP_SPEC + +#if TARGET_DEFAULT & 02 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!mc68000:%{!m68000:%{!m68332:%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}}}}\ +%{!ansi:%{m68010:-Dmc68010 }%{m68020:-Dmc68020 }%{mc68020:-Dmc68020 }%{m68030:-Dmc68030 }%{m68040:-Dmc68040 }%{m68020-40:-Dmc68020 -Dmc68030 -Dmc68040 }%{m68302:-Dmc68302 }%{m68332:-Dmc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-Dmc68360 }}}}}}}}}}}\ +%{m68010:-D__mc68010__ -D__mc68010 }%{m68020:-D__mc68020__ -D__mc68020 }%{mc68020:-D__mc68020__ -D__mc68020 }%{m68030:-D__mc68030__ -D__mc68030 }%{m68040:-D__mc68040__ -D__mc68040 }%{m68020-40:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 }%{m68302:-D__mc68302__ -D__mc68302 }%{m68332:-D__mc68332__ -D__mc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-D__mc68360__ -D__mc68360 }}}}}}}}}}" + +#else +#if TARGET_DEFAULT & 0100 + +/* -mfpa is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{m68881:-D__HAVE_68881__ }%{!m68881:-D__HAVE_FPA__ }}\ +%{!ansi:%{m68010:-Dmc68010 }%{m68020:-Dmc68020 }%{mc68020:-Dmc68020 }%{m68030:-Dmc68030 }%{m68040:-Dmc68040 }%{m68020-40:-Dmc68020 -Dmc68030 -Dmc68040 }%{m68302:-Dmc68302 }%{m68332:-Dmc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-Dmc68360 }}}}}}}}}}}\ +%{m68010:-D__mc68010__ -D__mc68010 }%{m68020:-D__mc68020__ -D__mc68020 }%{mc68020:-D__mc68020__ -D__mc68020 }%{m68030:-D__mc68030__ -D__mc68030 }%{m68040:-D__mc68040__ -D__mc68040 }%{m68020-40:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 }%{m68302:-D__mc68302__ -D__mc68302 }%{m68332:-D__mc68332__ -D__mc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-D__mc68360__ -D__mc68360 }}}}}}}}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{!ansi:%{m68010:-Dmc68010 }%{m68020:-Dmc68020 }%{mc68020:-Dmc68020 }%{m68030:-Dmc68030 }%{m68040:-Dmc68040 }%{m68020-40:-Dmc68020 -Dmc68030 -Dmc68040 }%{m68302:-Dmc68302 }%{m68332:-Dmc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-Dmc68360 }}}}}}}}}}}\ +%{m68010:-D__mc68010__ -D__mc68010 }%{m68020:-D__mc68020__ -D__mc68020 }%{mc68020:-D__mc68020__ -D__mc68020 }%{m68030:-D__mc68030__ -D__mc68030 }%{m68040:-D__mc68040__ -D__mc68040 }%{m68020-40:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 }%{m68302:-D__mc68302__ -D__mc68302 }%{m68332:-D__mc68332__ -D__mc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-D__mc68360__ -D__mc68360 }}}}}}}}}}" + +#endif +#endif + +#endif + +/* Pass flags to gas indicating which type of processor we have. */ + +#ifndef ASM_SPEC + +#define ASM_SPEC \ +"%{m68851}%{mno-68851}%{m68881}%{mno-68881}%{msoft-float:-mno-68881 }\ +%{m68000}%{mc68000}%{m68010}%{m68020}%{mc68020}%{m68030}%{m68040}%{m68020-40:-mc68040}%{m68302}%{m68332}%{!m68000:%{!mc68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-m68360}}}}}}}}}}" + +#endif + +#ifndef CC1_SPEC + +#define CC1_SPEC \ + "%{m68000:%{!m68881:-msoft-float }}%{m68302:-m68000}%{m68332:-m68020 -mnobitfield %{!m68881:-msoft-float}}%{!m68000:%{!mc68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-m68000}}}}}}}}}}" + +#endif + +#define HANDLE_SYSV_PRAGMA + +/* Boundary (in *bits*) on which stack pointer should be aligned. + The m68k/SVR4 convention is to keep the stack pointer longword aligned. */ + +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. + For m68k/SVR4, this is the next longword boundary. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 32 + +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + ((ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* Make arrays of chars word-aligned for the same reasons. */ +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + ((ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + +/* No data type wants to be aligned rounder than this. */ +#undef BIGGEST_ALIGNMENT +#define BIGGEST_ALIGNMENT 32 + +/* Other 68k targets don't have a way to align to more than a two-byte + boundary, so we override here. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\t.even\n"); \ + else \ + fprintf (FILE, "\t.align %d\n", (LOG)) +/* end of m68360-none.h */ diff --git a/gcc/config/m68k/m68k-aout.h b/gcc/config/m68k/m68k-aout.h new file mode 100755 index 0000000..b65f9fe --- /dev/null +++ b/gcc/config/m68k/m68k-aout.h @@ -0,0 +1,44 @@ +/* Definitions of target machine for GNU compiler. "naked" 68020, + a.out object files and debugging, version. + Copyright (C) 1994, 1996 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. */ + +/* This comment is here to see if it will keep Sun's cpp from dying. */ + +#include "m68k/m68k-none.h" +#include "m68k/m68kemb.h" +#include "aoutos.h" + +#define DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as uninitialized global + data. */ +#define BSS_SECTION_ASM_OP "\t.bss" + +/* A C statement (sans semicolon) to output to the stdio stream + FILE the assembler definition of uninitialized global DECL named + NAME whose size is SIZE bytes. The variable ROUNDED + is the size rounded up to whatever alignment the caller wants. + Try to use asm_output_bss to implement this macro. */ +/* a.out files typically can't handle arbitrary variable alignments so + define ASM_OUTPUT_BSS instead of ASM_OUTPUT_ALIGNED_BSS. */ +#define ASM_OUTPUT_BSS(FILE, DECL, NAME, SIZE, ROUNDED) \ + asm_output_bss ((FILE), (DECL), (NAME), (SIZE), (ROUNDED)) diff --git a/gcc/config/m68k/m68k-coff.h b/gcc/config/m68k/m68k-coff.h new file mode 100755 index 0000000..085dd95 --- /dev/null +++ b/gcc/config/m68k/m68k-coff.h @@ -0,0 +1,28 @@ +/* Definitions of target machine for GNU compiler. "naked" 68020, + COFF object files and debugging, version. + Copyright (C) 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. */ + +#define MOTOROLA /* Use Motorola syntax rather than MIT. */ + +#include "m68k/m68k-none.h" +#include "m68k/m68kemb.h" +#include "m68k/coff.h" + +/* end of m68k-coff.h */ diff --git a/gcc/config/m68k/m68k-none.h b/gcc/config/m68k/m68k-none.h new file mode 100755 index 0000000..c48ac3d --- /dev/null +++ b/gcc/config/m68k/m68k-none.h @@ -0,0 +1,197 @@ +/* Definitions of target machine for GNU compiler. "naked" 68020. + Copyright (C) 1994, 1996 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 "m68k/m68k.h" + +/* Default to m68k (m68020). */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT M68K_CPU_m68k +#endif + +/* These are values set by the configure script in TARGET_CPU_DEFAULT. + They are ((desired value for TARGET_DEFAULT) << 4) + sequential integer. + See m68k.h for the values (it should really define MASK_FOO so we can + use them). */ +#define M68K_CPU_m68k ((7 << 4) + 0) +#define M68K_CPU_m68000 ((0 << 4) + 1) +#define M68K_CPU_m68010 ((0 << 4) + 1) /* make same as m68000 */ +#define M68K_CPU_m68020 ((7 << 4) + 2) +#define M68K_CPU_m68030 ((7 << 4) + 3) +#define M68K_CPU_m68040 ((01007 << 4) + 4) +#define M68K_CPU_m68302 ((0 << 4) + 5) +#define M68K_CPU_m68332 ((1 << 4) + 6) + +/* This is tested for below, so if target wants to override this, it + just set this first in cover file. */ +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (TARGET_CPU_DEFAULT >> 4) +#endif + +/* Defaults for the various specs below. + These are collected here so we only test TARGET_CPU_DEFAULT once. */ +/* ??? CC1_CPU_DEFAULT_SPEC was copied over from the earlier version of + this file. However, it's not used anywhere here because it doesn't + seem to be necessary. */ +#if TARGET_CPU_DEFAULT == M68K_CPU_m68k || TARGET_CPU_DEFAULT == M68K_CPU_m68020 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68020 } -D__mc68020 -D__mc68020__" +#define ASM_CPU_DEFAULT_SPEC "-mc68020" +#define CC1_CPU_DEFAULT_SPEC "-m68020" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68000 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68000 } -D__mc68000 -D__mc68000__" +#define ASM_CPU_DEFAULT_SPEC "-mc68000" +#define CC1_CPU_DEFAULT_SPEC "-m68000" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68030 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68030 } -D__mc68030 -D__mc68030__" +#define ASM_CPU_DEFAULT_SPEC "-mc68030" +#define CC1_CPU_DEFAULT_SPEC "-m68030" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68040 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68040 } -D__mc68040 -D__mc68040__" +#define ASM_CPU_DEFAULT_SPEC "-mc68040" +#define CC1_CPU_DEFAULT_SPEC "-m68040" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68302 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68302 } -D__mc68302 -D__mc68302__" +#define ASM_CPU_DEFAULT_SPEC "-mc68302" +#define CC1_CPU_DEFAULT_SPEC "-m68302" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68332 +#define CPP_CPU_DEFAULT_SPEC "%{!ansi:-Dmc68332 -Dmcpu32 } -D__mc68332 -D__mc68332__ -D__mcpu32 -D__mcpu32__" +#define ASM_CPU_DEFAULT_SPEC "-mc68332" +#define CC1_CPU_DEFAULT_SPEC "-m68332" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif +#endif + +/* Always define mc68000. + Remember that GCC will automatically add __mc68000 and __mc68000__. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000" + +/* Define one of __HAVE_68881__, __HAVE_FPA__, __HAVE_SKY__, or nothing + (soft float), appropriately. */ +#undef CPP_FPU_SPEC +#if TARGET_DEFAULT & MASK_68881 +#define CPP_FPU_SPEC "\ +%{!mc68000:%{!m68000:%{!m68302:%{!mcpu32:%{!m68332:%{!m5200:%{!msoft-float:%{!mno-68881:%{!mfpa:%{!msky:-D__HAVE_68881__ }}}}}}}}}} \ +%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }%{msky:-D__HAVE_SKY__ }" +#else +/* This can't currently happen, but we code it anyway to show how it's done. */ +#if TARGET_DEFAULT & MASK_FPA +#define CPP_FPU_SPEC \ +"%{!msoft-float:%{m68881:-D__HAVE_68881__ }%{!m68881:-D__HAVE_FPA__ }}" +#else +#define CPP_FPU_SPEC "\ +%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }%{msky:-D__HAVE_SKY__ }" +#endif +#endif + +/* Names to predefine in the preprocessor for this target machine. + Other definitions depend on what the default cpu is and switches + given to the compiler: + + -m68000, -mc68000: define nothing else + -m68010: define mc68010 + -m68020, -mc68020: define mc68020 + -m68030: define mc68030 + -m68040: define mc68040 + -m68060: define mc68060 + -m68020-40: define mc68020 mc68030 mc68040 + -m68020-60: define mc68020 mc68030 mc68040 mc68060 + -m68302: define mc68302 + -m68332: define mc68332 mcpu32 + -mcpu32: define mcpu32 + -m5200: define mcf5200 + default: define as above appropriately + + GCC won't automatically add __'d versions, we have to mention them + explicitly. */ + +#undef CPP_SPEC +#define CPP_SPEC "\ +%(cpp_fpu)%{!ansi:%{m68302:-Dmc68302 }%{m68010:-Dmc68010 }%{m68020:-Dmc68020 }%{mc68020:-Dmc68020 }%{m68030:-Dmc68030 }%{m68040:-Dmc68040 }%{m68020-40:-Dmc68020 -Dmc68030 -Dmc68040 }%{m68020-60:-Dmc68020 -Dmc68030 -Dmc68040 -Dmc68060 }%{m68060:-Dmc68060 }%{mcpu32:-Dmcpu32 } %{m68332:-Dmc68332 -Dmcpu32 }%{m5200:-Dmcf5200 }} \ +%{m68302:-D__mc68302__ -D__mc68302 }%{m68010:-D__mc68010__ -D__mc68010 }%{m68020:-D__mc68020__ -D__mc68020 }%{mc68020:-D__mc68020__ -D__mc68020 }%{m68030:-D__mc68030__ -D__mc68030 }%{m68040:-D__mc68040__ -D__mc68040 }%{m68020-40:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 }%{m68020-60:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 -D__mc68060__ -D__mc68060 }%{m68060:-D__mc68060__ -D__mc68060 }%{mcpu32:-D__mcpu32__ -D__mcpu32 }%{m68332:-D__mc68332__ -D__mc68332 -D__mcpu32__ -D__mcpu32 }%{m5200:-D__mcf5200__ -D__mcf5200 } \ +%{!mc68000:%{!m68000:%{!m68302:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68020-60:%{!m68060:%{!mcpu32: %{!m68332:%{!m5200:%(cpp_cpu_default)}}}}}}}}}}}}}} \ +%(cpp_subtarget) \ +" + +/* Pass flags to gas indicating which type of processor we have. */ + +#undef ASM_SPEC +#define ASM_SPEC "\ +%{m68851}%{mno-68851}%{m68881}%{mno-68881}%{msoft-float:-mno-68881 }%{m68000}%{m68302}%{mc68000}%{m68010}%{m68020}%{mc68020}%{m68030}%{m68040}%{m68020-40:-mc68040 }%{m68020-60:-mc68040 }%{m68060}%{mcpu32}%{m68332}%{m5200}%{!mc68000:%{!m68000:%{!m68302:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68020-60:%{!m68060:%{!mcpu32:%{!m68332:%{!m5200:%(asm_cpu_default) }}}}}}}}}}}}}} \ +" + +/* cc1/cc1plus always receives all the -m flags. If the specs strings above + are consistent with the TARGET_OPTIONS flags in m68k.h, there should be no + need for any further cc1/cc1plus specs. */ + +#undef CC1_SPEC +#define CC1_SPEC "" + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ + +#define EXTRA_SPECS \ + { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \ + { "cpp_fpu", CPP_FPU_SPEC }, \ + { "cpp_subtarget", CPP_SUBTARGET_SPEC }, \ + { "asm_cpu_default", ASM_CPU_DEFAULT_SPEC }, \ +/*{ "cc1_cpu_default", CC1_CPU_DEFAULT__SPEC },*/ \ + SUBTARGET_EXTRA_SPECS + +#define CPP_SUBTARGET_SPEC "" +#define SUBTARGET_EXTRA_SPECS + +/* Avoid building multilib libraries for the defaults. + t-m68kbare doesn't support -mfpa in the multilib'd libraries, so we don't + either. + For targets not handled here, just build the full set of multilibs. + The default is m68k 99.9% of the time anyway. */ + +#if TARGET_CPU_DEFAULT == M68K_CPU_m68k || TARGET_CPU_DEFAULT == M68K_CPU_m68020 +#if TARGET_DEFAULT & MASK_68881 +#define MULTILIB_DEFAULTS { "m68020", "m68881" } +#else +#define MULTILIB_DEFAULTS { "m68020", "msoft-float" } +#endif +#endif + +#if TARGET_CPU_DEFAULT == M68K_CPU_m68000 || TARGET_CPU_DEFAULT == M68K_CPU_m68302 +#if TARGET_DEFAULT & MASK_68881 +#define MULTILIB_DEFAULTS { "m68000", "m68881" } +#else +#define MULTILIB_DEFAULTS { "m68000", "msoft-float" } +#endif +#endif diff --git a/gcc/config/m68k/m68k-psos.h b/gcc/config/m68k/m68k-psos.h new file mode 100755 index 0000000..8e5b843 --- /dev/null +++ b/gcc/config/m68k/m68k-psos.h @@ -0,0 +1,67 @@ +/* Definitions of a target machine for the GNU compiler: + 68040 running pSOS, ELF object files, DBX debugging. + Copyright (C) 1996 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. */ + + +/* Use MOTOROLA assembler syntax, as gas is configured that way and + glibc also seems to use it. Must come BEFORE m68k.h! */ + +#define MOTOROLA + +/* Get generic m68k definitions. */ + +#include "m68k/m68k.h" +#include "m68k/m68kemb.h" + +/* Default processor type is a (pure) 68040 with 68881 emulation using + the floating-point support package. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_68040_ONLY|MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Options passed to CPP, GAS, CC1 and CC1PLUS. We override + m68k-none.h for consistency with TARGET_DEFAULT. */ + +#undef CPP_SPEC +#define CPP_SPEC \ +"%{!mc68000:%{!m68000:%{!m68332:%{!msoft-float:-D__HAVE_68881__ }}}}\ +%{!ansi:-Dmc68000 %{m68010:-Dmc68010 }%{m68020:-Dmc68020 }%{mc68020:-Dmc68020 }%{m68030:-Dmc68030 }%{m68040:-Dmc68040 }%{m68020-40:-Dmc68020 -Dmc68030 -Dmc68040 }%{m68302:-Dmc68302 }%{m68332:-Dmc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-Dmc68040 }}}}}}}}}}}\ +-D__mc68000__ -D__mc68000 %{m68010:-D__mc68010__ -D__mc68010 }%{m68020:-D__mc68020__ -D__mc68020 }%{mc68020:-D__mc68020__ -D__mc68020 }%{m68030:-D__mc68030__ -D__mc68030 }%{m68040:-D__mc68040__ -D__mc68040 }%{m68020-40:-D__mc68020__ -D__mc68030__ -D__mc68040__ -D__mc68020 -D__mc68030 -D__mc68040 }%{m68302:-D__mc68302__ -D__mc68302 }%{m68332:-D__mc68332__ -D__mc68332 }%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-D__mc68040__ -D__mc68040 }}}}}}}}}}" + +#undef ASM_SPEC +#define ASM_SPEC \ +"%{m68851}%{mno-68851}%{m68881}%{mno-68881}%{msoft-float:-mno-68881 }\ +%{m68000}%{mc68000}%{m68010}%{m68020}%{mc68020}%{m68030}%{m68040}%{m68020-40:-mc68040}%{m68302}%{m68332}%{!m68000:%{!mc68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-mc68040}}}}}}}}}}" + +#undef CC1_SPEC +#define CC1_SPEC \ + "%{m68000:%{!m68881:-msoft-float }}%{m68302:-m68000}%{m68332:-m68020 -mnobitfield %{!m68881:-msoft-float}}%{!m68000:%{!mc68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-m68040}}}}}}}}}}" + +#undef CC1PLUS_SPEC +#define CC1PLUS_SPEC \ + "%{m68000:%{!m68881:-msoft-float }}%{m68302:-m68000}%{m68332:-m68020 -mnobitfield %{!m68881:-msoft-float}}%{!m68000:%{!mc68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:-m68040}}}}}}}}}}" + + +/* Get processor-independent pSOS definitions. */ + +#include "psos.h" + + +/* end of m68k-psos.h */ diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c new file mode 100755 index 0000000..244fa7f --- /dev/null +++ b/gcc/config/m68k/m68k.c @@ -0,0 +1,3393 @@ +/* Subroutines for insn-output.c for Motorola 68000 family. + Copyright (C) 1987, 93-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Some output-actions in m68k.md need these. */ +#include "config.h" +#include "system.h" +#include "tree.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" +#include "recog.h" +#include "toplev.h" + +/* Needed for use_return_insn. */ +#include "flags.h" + +#ifdef SUPPORT_SUN_FPA + +/* Index into this array by (register number >> 3) to find the + smallest class which contains that register. */ +enum reg_class regno_reg_class[] + = { DATA_REGS, ADDR_REGS, FP_REGS, + LO_FPA_REGS, LO_FPA_REGS, FPA_REGS, FPA_REGS }; + +#endif /* defined SUPPORT_SUN_FPA */ + +/* This flag is used to communicate between movhi and ASM_OUTPUT_CASE_END, + if SGS_SWITCH_TABLE. */ +int switch_table_difference_label_flag; + +static rtx find_addr_reg (); +rtx legitimize_pic_address (); + + +/* Alignment to use for loops and jumps */ +/* Specify power of two alignment used for loops. */ +char *m68k_align_loops_string; +/* Specify power of two alignment used for non-loop jumps. */ +char *m68k_align_jumps_string; +/* Specify power of two alignment used for functions. */ +char *m68k_align_funcs_string; + +/* Specify power of two alignment used for loops. */ +int m68k_align_loops; +/* Specify power of two alignment used for non-loop jumps. */ +int m68k_align_jumps; +/* Specify power of two alignment used for functions. */ +int m68k_align_funcs; + +/* Nonzero if the last compare/test insn had FP operands. The + sCC expanders peek at this to determine what to do for the + 68060, which has no fsCC instructions. */ +int m68k_last_compare_had_fp_operands; + +/* Sometimes certain combinations of command options do not make + sense on a particular target machine. You can define a macro + `OVERRIDE_OPTIONS' to take account of this. This macro, if + defined, is executed once just after all the command options have + been parsed. + + Don't use this macro to turn on various extra optimizations for + `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ + +void +override_options () +{ + int def_align; + + def_align = 1; + + /* Validate -malign-loops= value, or provide default */ + if (m68k_align_loops_string) + { + m68k_align_loops = atoi (m68k_align_loops_string); + if (m68k_align_loops < 1 || m68k_align_loops > MAX_CODE_ALIGN) + fatal ("-malign-loops=%d is not between 1 and %d", + m68k_align_loops, MAX_CODE_ALIGN); + } + else + m68k_align_loops = def_align; + + /* Validate -malign-jumps= value, or provide default */ + if (m68k_align_jumps_string) + { + m68k_align_jumps = atoi (m68k_align_jumps_string); + if (m68k_align_jumps < 1 || m68k_align_jumps > MAX_CODE_ALIGN) + fatal ("-malign-jumps=%d is not between 1 and %d", + m68k_align_jumps, MAX_CODE_ALIGN); + } + else + m68k_align_jumps = def_align; + + /* Validate -malign-functions= value, or provide default */ + if (m68k_align_funcs_string) + { + m68k_align_funcs = atoi (m68k_align_funcs_string); + if (m68k_align_funcs < 1 || m68k_align_funcs > MAX_CODE_ALIGN) + fatal ("-malign-functions=%d is not between 1 and %d", + m68k_align_funcs, MAX_CODE_ALIGN); + } + else + m68k_align_funcs = def_align; +} + +/* Emit a (use pic_offset_table_rtx) if we used PIC relocation in the + function at any time during the compilation process. In the future + we should try and eliminate the USE if we can easily determine that + all PIC references were deleted from the current function. That would + save an address register */ + +void +finalize_pic () +{ + if (flag_pic && current_function_uses_pic_offset_table) + { + rtx insn = gen_rtx_USE (VOIDmode, pic_offset_table_rtx); + emit_insn_after (insn, get_insns ()); + emit_insn (insn); + } +} + + +/* This function generates the assembly code for function entry. + STREAM is a stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. + Refer to the array `regs_ever_live' to determine which registers + to save; `regs_ever_live[I]' is nonzero if register number I + is ever used in the function. This function is responsible for + knowing which registers should not be saved even if used. */ + + +/* Note that the order of the bit mask for fmovem is the opposite + of the order for movem! */ + + +void +output_function_prologue (stream, size) + FILE *stream; + int size; +{ + register int regno; + register int mask = 0; + int num_saved_regs = 0; + extern char call_used_regs[]; + int fsize = (size + 3) & -4; + int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset; + + + if (frame_pointer_needed) + { + if (fsize == 0 && TARGET_68040) + { + /* on the 68040, pea + move is faster than link.w 0 */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n", + reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], + reg_names[FRAME_POINTER_REGNUM]); +#else + asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n", + reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], + reg_names[FRAME_POINTER_REGNUM]); +#endif + } + else if (fsize < 0x8000) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tlink.w %s,%0I%d\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#else + asm_fprintf (stream, "\tlink %s,%0I%d\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#endif + } + else if (TARGET_68020) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tlink.l %s,%0I%d\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#else + asm_fprintf (stream, "\tlink %s,%0I%d\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#endif + } + else + { + /* Adding negative number is faster on the 68040. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#else + asm_fprintf (stream, "\tlink %s,%0I0\n\taddl %0I%d,%Rsp\n", + reg_names[FRAME_POINTER_REGNUM], -fsize); +#endif + } + if (dwarf2out_do_frame ()) + { + char *l; + l = (char *) dwarf2out_cfi_label (); + cfa_store_offset += 4; + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, cfa_offset); + dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_store_offset); + cfa_store_offset += fsize; + } + } + else if (fsize) + { + if (fsize + 4 < 0x8000) + { +#ifndef NO_ADDSUB_Q + if (fsize + 4 <= 8) + { + if (!TARGET_5200) + { + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tsubq.w %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\tsubqw %0I%d,%Rsp\n", fsize + 4); +#endif + } + else + { + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tsubq.l %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\tsubql %0I%d,%Rsp\n", fsize + 4); +#endif + } + } + else if (fsize + 4 <= 16 && TARGET_CPU32) + { + /* On the CPU32 it is faster to use two subqw instructions to + subtract a small integer (8 < N <= 16) to a register. */ + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tsubq.w %0I8,%Rsp\n\tsubq.w %0I%d,%Rsp\n", + fsize + 4); +#else + asm_fprintf (stream, "\tsubqw %0I8,%Rsp\n\tsubqw %0I%d,%Rsp\n", + fsize + 4); +#endif + } + else +#endif /* not NO_ADDSUB_Q */ + if (TARGET_68040) + { + /* Adding negative number is faster on the 68040. */ + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4)); +#else + asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", - (fsize + 4)); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", - (fsize + 4)); +#else + asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", - (fsize + 4)); +#endif + } + } + else + { + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4)); +#else + asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", - (fsize + 4)); +#endif + } + if (dwarf2out_do_frame ()) + { + cfa_store_offset += fsize; + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); + } + } +#ifdef SUPPORT_SUN_FPA + for (regno = 24; regno < 56; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfpmovd %s,-(%Rsp)\n", + reg_names[regno]); +#else + asm_fprintf (stream, "\tfpmoved %s,%Rsp@-\n", + reg_names[regno]); +#endif + if (dwarf2out_do_frame ()) + { + char *l = dwarf2out_cfi_label (); + + cfa_store_offset += 8; + if (! frame_pointer_needed) + { + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); + } + dwarf2out_reg_save (l, regno, -cfa_store_offset); + } + } +#endif + if (TARGET_68881) + { + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + mask |= 1 << (regno - 16); + num_saved_regs++; + } + if ((mask & 0xff) != 0) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfmovm %0I0x%x,-(%Rsp)\n", mask & 0xff); +#else + asm_fprintf (stream, "\tfmovem %0I0x%x,%Rsp@-\n", mask & 0xff); +#endif + if (dwarf2out_do_frame ()) + { + char *l = (char *) dwarf2out_cfi_label (); + int n_regs; + + cfa_store_offset += num_saved_regs * 12; + if (! frame_pointer_needed) + { + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); + } + for (regno = 16, n_regs = 0; regno < 24; regno++) + if (mask & (1 << (regno - 16))) + dwarf2out_reg_save (l, regno, + -cfa_store_offset + n_regs++ * 12); + } + } + mask = 0; + num_saved_regs = 0; + } + for (regno = 0; regno < 16; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + mask |= 1 << (15 - regno); + num_saved_regs++; + } + if (frame_pointer_needed) + { + mask &= ~ (1 << (15 - FRAME_POINTER_REGNUM)); + num_saved_regs--; + } + +#if NEED_PROBE +#ifdef MOTOROLA +#ifdef CRDS + asm_fprintf (stream, "\ttstl %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4); +#else + asm_fprintf (stream, "\ttst.l %d(%Rsp)\n", NEED_PROBE - num_saved_regs * 4); +#endif +#else + asm_fprintf (stream, "\ttstl %Rsp@(%d)\n", NEED_PROBE - num_saved_regs * 4); +#endif +#endif + + if (num_saved_regs <= 2) + { + /* Store each separately in the same order moveml uses. + Using two movel instructions instead of a single moveml + is about 15% faster for the 68020 and 68030 at no expense + in code size */ + + int i; + + /* Undo the work from above. */ + for (i = 0; i< 16; i++) + if (mask & (1 << i)) + { + asm_fprintf (stream, +#ifdef MOTOROLA + "\t%Omove.l %s,-(%Rsp)\n", +#else + "\tmovel %s,%Rsp@-\n", +#endif + reg_names[15 - i]); + if (dwarf2out_do_frame ()) + { + char *l = (char *) dwarf2out_cfi_label (); + + cfa_store_offset += 4; + if (! frame_pointer_needed) + { + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); + } + dwarf2out_reg_save (l, 15 - i, -cfa_store_offset); + } + } + } + else if (mask) + { + if (TARGET_5200) + { + /* The coldfire does not support the predecrement form of the + movml instruction, so we must adjust the stack pointer and + then use the plain address register indirect mode. We also + have to invert the register save mask to use the new mode. + + FIXME: if num_saved_regs was calculated earlier, we could + combine the stack pointer adjustment with any adjustment + done when the initial stack frame is created. This would + save an instruction */ + + int newmask = 0; + int i; + + for (i = 0; i < 16; i++) + if (mask & (1 << i)) + newmask |= (1 << (15-i)); + +#ifdef MOTOROLA + asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", -num_saved_regs*4); + asm_fprintf (stream, "\tmovm.l %0I0x%x,(%Rsp)\n", newmask); +#else + asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", -num_saved_regs*4); + asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@\n", newmask); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tmovm.l %0I0x%x,-(%Rsp)\n", mask); +#else + asm_fprintf (stream, "\tmoveml %0I0x%x,%Rsp@-\n", mask); +#endif + } + if (dwarf2out_do_frame ()) + { + char *l = (char *) dwarf2out_cfi_label (); + int n_regs; + + cfa_store_offset += num_saved_regs * 4; + if (! frame_pointer_needed) + { + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); + } + for (regno = 0, n_regs = 0; regno < 16; regno++) + if (mask & (1 << (15 - regno))) + dwarf2out_reg_save (l, regno, + -cfa_store_offset + n_regs++ * 4); + } + } + if (flag_pic && current_function_uses_pic_offset_table) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n", + reg_names[PIC_OFFSET_TABLE_REGNUM]); +#else + asm_fprintf (stream, "\tmovel %0I__GLOBAL_OFFSET_TABLE_, %s\n", + reg_names[PIC_OFFSET_TABLE_REGNUM]); + asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n", + reg_names[PIC_OFFSET_TABLE_REGNUM], + reg_names[PIC_OFFSET_TABLE_REGNUM]); +#endif + } +} + +/* Return true if this function's epilogue can be output as RTL. */ + +int +use_return_insn () +{ + int regno; + + if (!reload_completed || frame_pointer_needed || get_frame_size () != 0) + return 0; + + /* Copied from output_function_epilogue (). We should probably create a + separate layout routine to perform the common work. */ + + for (regno = 0 ; regno < FIRST_PSEUDO_REGISTER ; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + return 0; + + return 1; +} + +/* This function generates the assembly code for function exit, + on machines that need it. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + It should use the frame pointer only, if there is a frame pointer. + This is mandatory because of alloca; we also take advantage of it to + omit stack adjustments before returning. */ + +void +output_function_epilogue (stream, size) + FILE *stream; + int size; +{ + register int regno; + register int mask, fmask; + register int nregs; + int offset, foffset, fpoffset; + extern char call_used_regs[]; + int fsize = (size + 3) & -4; + int big = 0; + rtx insn = get_last_insn (); + int restore_from_sp = 0; + + /* If the last insn was a BARRIER, we don't have to write any code. */ + if (GET_CODE (insn) == NOTE) + insn = prev_nonnote_insn (insn); + if (insn && GET_CODE (insn) == BARRIER) + { + /* Output just a no-op so that debuggers don't get confused + about which function the pc is in at this address. */ + asm_fprintf (stream, "\tnop\n"); + return; + } + +#ifdef FUNCTION_BLOCK_PROFILER_EXIT + if (profile_block_flag == 2) + { + FUNCTION_BLOCK_PROFILER_EXIT (stream); + } +#endif + +#ifdef FUNCTION_EXTRA_EPILOGUE + FUNCTION_EXTRA_EPILOGUE (stream, size); +#endif + nregs = 0; fmask = 0; fpoffset = 0; +#ifdef SUPPORT_SUN_FPA + for (regno = 24 ; regno < 56 ; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + nregs++; + fpoffset = nregs * 8; +#endif + nregs = 0; + if (TARGET_68881) + { + for (regno = 16; regno < 24; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + nregs++; + fmask |= 1 << (23 - regno); + } + } + foffset = fpoffset + nregs * 12; + nregs = 0; mask = 0; + if (frame_pointer_needed) + regs_ever_live[FRAME_POINTER_REGNUM] = 0; + for (regno = 0; regno < 16; regno++) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + nregs++; + mask |= 1 << regno; + } + offset = foffset + nregs * 4; + /* FIXME : leaf_function_p below is too strong. + What we really need to know there is if there could be pending + stack adjustment needed at that point. */ + restore_from_sp = ! frame_pointer_needed + || (! current_function_calls_alloca && leaf_function_p ()); + if (offset + fsize >= 0x8000 + && ! restore_from_sp + && (mask || fmask || fpoffset)) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize); +#else + asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize); +#endif + fsize = 0, big = 1; + } + if (TARGET_5200 || nregs <= 2) + { + /* Restore each separately in the same order moveml does. + Using two movel instructions instead of a single moveml + is about 15% faster for the 68020 and 68030 at no expense + in code size. */ + + int i; + + /* Undo the work from above. */ + for (i = 0; i< 16; i++) + if (mask & (1 << i)) + { + if (big) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n", + offset + fsize, + reg_names[FRAME_POINTER_REGNUM], + reg_names[i]); +#else + asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n", + reg_names[FRAME_POINTER_REGNUM], + offset + fsize, reg_names[i]); +#endif + } + else if (restore_from_sp) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\t%Omove.l (%Rsp)+,%s\n", + reg_names[i]); +#else + asm_fprintf (stream, "\tmovel %Rsp@+,%s\n", + reg_names[i]); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\t%Omove.l -%d(%s),%s\n", + offset + fsize, + reg_names[FRAME_POINTER_REGNUM], + reg_names[i]); +#else + asm_fprintf (stream, "\tmovel %s@(-%d),%s\n", + reg_names[FRAME_POINTER_REGNUM], + offset + fsize, reg_names[i]); +#endif + } + offset = offset - 4; + } + } + else if (mask) + { + if (big) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n", + offset + fsize, + reg_names[FRAME_POINTER_REGNUM], + mask); +#else + asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n", + reg_names[FRAME_POINTER_REGNUM], + offset + fsize, mask); +#endif + } + else if (restore_from_sp) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tmovm.l (%Rsp)+,%0I0x%x\n", mask); +#else + asm_fprintf (stream, "\tmoveml %Rsp@+,%0I0x%x\n", mask); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tmovm.l -%d(%s),%0I0x%x\n", + offset + fsize, + reg_names[FRAME_POINTER_REGNUM], + mask); +#else + asm_fprintf (stream, "\tmoveml %s@(-%d),%0I0x%x\n", + reg_names[FRAME_POINTER_REGNUM], + offset + fsize, mask); +#endif + } + } + if (fmask) + { + if (big) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n", + foffset + fsize, + reg_names[FRAME_POINTER_REGNUM], + fmask); +#else + asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n", + reg_names[FRAME_POINTER_REGNUM], + foffset + fsize, fmask); +#endif + } + else if (restore_from_sp) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfmovm (%Rsp)+,%0I0x%x\n", fmask); +#else + asm_fprintf (stream, "\tfmovem %Rsp@+,%0I0x%x\n", fmask); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfmovm -%d(%s),%0I0x%x\n", + foffset + fsize, + reg_names[FRAME_POINTER_REGNUM], + fmask); +#else + asm_fprintf (stream, "\tfmovem %s@(-%d),%0I0x%x\n", + reg_names[FRAME_POINTER_REGNUM], + foffset + fsize, fmask); +#endif + } + } + if (fpoffset != 0) + for (regno = 55; regno >= 24; regno--) + if (regs_ever_live[regno] && ! call_used_regs[regno]) + { + if (big) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n", + fpoffset + fsize, + reg_names[FRAME_POINTER_REGNUM], + reg_names[regno]); +#else + asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n", + reg_names[FRAME_POINTER_REGNUM], + fpoffset + fsize, reg_names[regno]); +#endif + } + else if (restore_from_sp) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfpmovd (%Rsp)+,%s\n", + reg_names[regno]); +#else + asm_fprintf (stream, "\tfpmoved %Rsp@+, %s\n", + reg_names[regno]); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tfpmovd -%d(%s), %s\n", + fpoffset + fsize, + reg_names[FRAME_POINTER_REGNUM], + reg_names[regno]); +#else + asm_fprintf (stream, "\tfpmoved %s@(-%d), %s\n", + reg_names[FRAME_POINTER_REGNUM], + fpoffset + fsize, reg_names[regno]); +#endif + } + fpoffset -= 8; + } + if (frame_pointer_needed) + fprintf (stream, "\tunlk %s\n", + reg_names[FRAME_POINTER_REGNUM]); + else if (fsize) + { +#ifndef NO_ADDSUB_Q + if (fsize + 4 <= 8) + { + if (!TARGET_5200) + { +#ifdef MOTOROLA + asm_fprintf (stream, "\taddq.w %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\taddqw %0I%d,%Rsp\n", fsize + 4); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\taddq.l %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\taddql %0I%d,%Rsp\n", fsize + 4); +#endif + } + } + else if (fsize + 4 <= 16 && TARGET_CPU32) + { + /* On the CPU32 it is faster to use two addqw instructions to + add a small integer (8 < N <= 16) to a register. */ + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\taddq.w %0I8,%Rsp\n\taddq.w %0I%d,%Rsp\n", + fsize + 4); +#else + asm_fprintf (stream, "\taddqw %0I8,%Rsp\n\taddqw %0I%d,%Rsp\n", + fsize + 4); +#endif + } + else +#endif /* not NO_ADDSUB_Q */ + if (fsize + 4 < 0x8000) + { + if (TARGET_68040) + { + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4); +#endif + } + else + { +#ifdef MOTOROLA + asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4); +#endif + } + } + else + { + /* asm_fprintf() cannot handle %. */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4); +#else + asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4); +#endif + } + } + if (current_function_pops_args) + asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args); + else + fprintf (stream, "\trts\n"); +} + +/* Similar to general_operand, but exclude stack_pointer_rtx. */ + +int +not_sp_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return op != stack_pointer_rtx && general_operand (op, mode); +} + +/* Return TRUE if X is a valid comparison operator for the dbcc + instruction. + + Note it rejects floating point comparison operators. + (In the future we could use Fdbcc). + + It also rejects some comparisons when CC_NO_OVERFLOW is set. */ + +int +valid_dbcc_comparison_p (x, mode) + rtx x; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + switch (GET_CODE (x)) + { + case EQ: case NE: case GTU: case LTU: + case GEU: case LEU: + return 1; + + /* Reject some when CC_NO_OVERFLOW is set. This may be over + conservative */ + case GT: case LT: case GE: case LE: + return ! (cc_prev_status.flags & CC_NO_OVERFLOW); + default: + return 0; + } +} + +/* Return non-zero if flags are currently in the 68881 flag register. */ +int +flags_in_68881 () +{ + /* We could add support for these in the future */ + return cc_status.flags & CC_IN_68881; +} + +/* Output a dbCC; jCC sequence. Note we do not handle the + floating point version of this sequence (Fdbcc). We also + do not handle alternative conditions when CC_NO_OVERFLOW is + set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will + kick those out before we get here. */ + +void +output_dbcc_and_branch (operands) + rtx *operands; +{ + switch (GET_CODE (operands[3])) + { + case EQ: +#ifdef MOTOROLA + output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands); +#else + output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands); +#endif + break; + + case NE: +#ifdef MOTOROLA + output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands); +#else + output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands); +#endif + break; + + case GT: +#ifdef MOTOROLA + output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands); +#else + output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands); +#endif + break; + + case GTU: +#ifdef MOTOROLA + output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands); +#else + output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands); +#endif + break; + + case LT: +#ifdef MOTOROLA + output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands); +#else + output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands); +#endif + break; + + case LTU: +#ifdef MOTOROLA + output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands); +#else + output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands); +#endif + break; + + case GE: +#ifdef MOTOROLA + output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands); +#else + output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands); +#endif + break; + + case GEU: +#ifdef MOTOROLA + output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands); +#else + output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands); +#endif + break; + + case LE: +#ifdef MOTOROLA + output_asm_insn ("dble %0,%l1\n\tjble %l2", operands); +#else + output_asm_insn ("dble %0,%l1\n\tjle %l2", operands); +#endif + break; + + case LEU: +#ifdef MOTOROLA + output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands); +#else + output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands); +#endif + break; + + default: + abort (); + } + + /* If the decrement is to be done in SImode, then we have + to compensate for the fact that dbcc decrements in HImode. */ + switch (GET_MODE (operands[0])) + { + case SImode: +#ifdef MOTOROLA + output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands); +#else + output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands); +#endif + break; + + case HImode: + break; + + default: + abort (); + } +} + +char * +output_scc_di(op, operand1, operand2, dest) + rtx op; + rtx operand1; + rtx operand2; + rtx dest; +{ + rtx loperands[7]; + enum rtx_code op_code = GET_CODE (op); + + /* This does not produce a usefull cc. */ + CC_STATUS_INIT; + + /* The m68k cmp.l instruction requires operand1 to be a reg as used + below. Swap the operands and change the op if these requirements + are not fulfilled. */ + if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG) + { + rtx tmp = operand1; + + operand1 = operand2; + operand2 = tmp; + op_code = swap_condition (op_code); + } + loperands[0] = operand1; + if (GET_CODE (operand1) == REG) + loperands[1] = gen_rtx_REG (SImode, REGNO (operand1) + 1); + else + loperands[1] = adj_offsettable_operand (operand1, 4); + if (operand2 != const0_rtx) + { + loperands[2] = operand2; + if (GET_CODE (operand2) == REG) + loperands[3] = gen_rtx_REG (SImode, REGNO (operand2) + 1); + else + loperands[3] = adj_offsettable_operand (operand2, 4); + } + loperands[4] = gen_label_rtx(); + if (operand2 != const0_rtx) + { +#ifdef MOTOROLA +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands); +#else + output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands); +#endif +#else +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands); +#else + output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands); +#endif +#endif + } + else + { + if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[0])) + output_asm_insn ("tst%.l %0", loperands); + else + { +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.w %0,%#0", loperands); +#else + output_asm_insn ("cmp%.w %#0,%0", loperands); +#endif + } + +#ifdef MOTOROLA + output_asm_insn ("jbne %l4", loperands); +#else + output_asm_insn ("jne %l4", loperands); +#endif + + if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[1])) + output_asm_insn ("tst%.l %1", loperands); + else + { +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.w %1,%#0", loperands); +#else + output_asm_insn ("cmp%.w %#0,%1", loperands); +#endif + } + } + + loperands[5] = dest; + + switch (op_code) + { + case EQ: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("seq %5", loperands); + break; + + case NE: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sne %5", loperands); + break; + + case GT: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("shi %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("shi %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sgt %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case GTU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("shi %5", loperands); + break; + + case LT: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("scs %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("scs %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("slt %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case LTU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("scs %5", loperands); + break; + + case GE: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("scc %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("scc %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sge %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case GEU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("scc %5", loperands); + break; + + case LE: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("sls %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("sls %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sle %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case LEU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sls %5", loperands); + break; + + default: + abort (); + } + return ""; +} + +char * +output_btst (operands, countop, dataop, insn, signpos) + rtx *operands; + rtx countop, dataop; + rtx insn; + int signpos; +{ + operands[0] = countop; + operands[1] = dataop; + + if (GET_CODE (countop) == CONST_INT) + { + register int count = INTVAL (countop); + /* If COUNT is bigger than size of storage unit in use, + advance to the containing unit of same size. */ + if (count > signpos) + { + int offset = (count & ~signpos) / 8; + count = count & signpos; + operands[1] = dataop = adj_offsettable_operand (dataop, offset); + } + if (count == signpos) + cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; + else + cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; + + /* These three statements used to use next_insns_test_no... + but it appears that this should do the same job. */ + if (count == 31 + && next_insn_tests_no_inequality (insn)) + return "tst%.l %1"; + if (count == 15 + && next_insn_tests_no_inequality (insn)) + return "tst%.w %1"; + if (count == 7 + && next_insn_tests_no_inequality (insn)) + return "tst%.b %1"; + + cc_status.flags = CC_NOT_NEGATIVE; + } + return "btst %0,%1"; +} + +/* Returns 1 if OP is either a symbol reference or a sum of a symbol + reference and a constant. */ + +int +symbolic_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + switch (GET_CODE (op)) + { + case SYMBOL_REF: + case LABEL_REF: + return 1; + + case CONST: + op = XEXP (op, 0); + return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF + || GET_CODE (XEXP (op, 0)) == LABEL_REF) + && GET_CODE (XEXP (op, 1)) == CONST_INT); + +#if 0 /* Deleted, with corresponding change in m68k.h, + so as to fit the specs. No CONST_DOUBLE is ever symbolic. */ + case CONST_DOUBLE: + return GET_MODE (op) == mode; +#endif + + default: + return 0; + } +} + +/* Check for sign_extend or zero_extend. Used for bit-count operands. */ + +int +extend_operator(x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode != VOIDmode && GET_MODE(x) != mode) + return 0; + switch (GET_CODE(x)) + { + case SIGN_EXTEND : + case ZERO_EXTEND : + return 1; + default : + return 0; + } +} + + +/* Legitimize PIC addresses. If the address is already + position-independent, we return ORIG. Newly generated + position-independent addresses go to REG. If we need more + than one register, we lose. + + An address is legitimized by making an indirect reference + through the Global Offset Table with the name of the symbol + used as an offset. + + The assembler and linker are responsible for placing the + address of the symbol in the GOT. The function prologue + is responsible for initializing a5 to the starting address + of the GOT. + + The assembler is also responsible for translating a symbol name + into a constant displacement from the start of the GOT. + + A quick example may make things a little clearer: + + When not generating PIC code to store the value 12345 into _foo + we would generate the following code: + + movel #12345, _foo + + When generating PIC two transformations are made. First, the compiler + loads the address of foo into a register. So the first transformation makes: + + lea _foo, a0 + movel #12345, a0@ + + The code in movsi will intercept the lea instruction and call this + routine which will transform the instructions into: + + movel a5@(_foo:w), a0 + movel #12345, a0@ + + + That (in a nutshell) is how *all* symbol and label references are + handled. */ + +rtx +legitimize_pic_address (orig, mode, reg) + rtx orig, reg; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + rtx pic_ref = orig; + + /* First handle a simple SYMBOL_REF or LABEL_REF */ + if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF) + { + if (reg == 0) + abort (); + + pic_ref = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, + pic_offset_table_rtx, orig)); + current_function_uses_pic_offset_table = 1; + if (reload_in_progress) + regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; + RTX_UNCHANGING_P (pic_ref) = 1; + emit_move_insn (reg, pic_ref); + return reg; + } + else if (GET_CODE (orig) == CONST) + { + rtx base; + + /* Make sure this is CONST has not already been legitimized */ + if (GET_CODE (XEXP (orig, 0)) == PLUS + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) + return orig; + + if (reg == 0) + abort (); + + /* legitimize both operands of the PLUS */ + if (GET_CODE (XEXP (orig, 0)) == PLUS) + { + base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); + orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, + base == reg ? 0 : reg); + } + else abort (); + + if (GET_CODE (orig) == CONST_INT) + return plus_constant_for_output (base, INTVAL (orig)); + pic_ref = gen_rtx_PLUS (Pmode, base, orig); + /* Likewise, should we set special REG_NOTEs here? */ + } + return pic_ref; +} + + +typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD; + +#define USE_MOVQ(i) ((unsigned)((i) + 128) <= 255) + +CONST_METHOD +const_method (constant) + rtx constant; +{ + int i; + unsigned u; + + i = INTVAL (constant); + if (USE_MOVQ (i)) + return MOVQ; + + /* The Coldfire doesn't have byte or word operations. */ + /* FIXME: This may not be useful for the m68060 either */ + if (!TARGET_5200) + { + /* if -256 < N < 256 but N is not in range for a moveq + N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */ + if (USE_MOVQ (i ^ 0xff)) + return NOTB; + /* Likewise, try with not.w */ + if (USE_MOVQ (i ^ 0xffff)) + return NOTW; + /* This is the only value where neg.w is useful */ + if (i == -65408) + return NEGW; + /* Try also with swap */ + u = i; + if (USE_MOVQ ((u >> 16) | (u << 16))) + return SWAP; + } + /* Otherwise, use move.l */ + return MOVL; +} + +int +const_int_cost (constant) + rtx constant; +{ + switch (const_method (constant)) + { + case MOVQ : + /* Constants between -128 and 127 are cheap due to moveq */ + return 0; + case NOTB : + case NOTW : + case NEGW : + case SWAP : + /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */ + return 1; + case MOVL : + return 2; + default : + abort (); + } +} + +char * +output_move_const_into_data_reg (operands) + rtx *operands; +{ + int i; + + i = INTVAL (operands[1]); + switch (const_method (operands[1])) + { + case MOVQ : +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0"; +#else + return "moveq %1,%0"; +#endif + case NOTB : + operands[1] = GEN_INT (i ^ 0xff); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tnot%.b %0"; +#else + return "moveq %1,%0\n\tnot%.b %0"; +#endif + case NOTW : + operands[1] = GEN_INT (i ^ 0xffff); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tnot%.w %0"; +#else + return "moveq %1,%0\n\tnot%.w %0"; +#endif + case NEGW : +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %#-128,%0\n\tneg%.w %0"; +#else + return "moveq %#-128,%0\n\tneg%.w %0"; +#endif + case SWAP : + { + unsigned u = i; + + operands[1] = GEN_INT ((u << 16) | (u >> 16)); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tswap %0"; +#else + return "moveq %1,%0\n\tswap %0"; +#endif + } + case MOVL : + return "move%.l %1,%0"; + default : + abort (); + } +} + +char * +output_move_simode_const (operands) + rtx *operands; +{ + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return "clr%.l %0"; + else if (operands[1] == const0_rtx + && ADDRESS_REG_P (operands[0])) + return "sub%.l %0,%0"; + else if (DATA_REG_P (operands[0])) + return output_move_const_into_data_reg (operands); + else if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return "move%.w %1,%0"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return "pea %a1"; + return "move%.l %1,%0"; +} + +char * +output_move_simode (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT) + return output_move_simode_const (operands); + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && push_operand (operands[0], SImode)) + return "pea %a1"; + else if ((GET_CODE (operands[1]) == SYMBOL_REF + || GET_CODE (operands[1]) == CONST) + && ADDRESS_REG_P (operands[0])) + return "lea %a1,%0"; + return "move%.l %1,%0"; +} + +char * +output_move_himode (operands) + rtx *operands; +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return "clr%.w %0"; + else if (operands[1] == const0_rtx + && ADDRESS_REG_P (operands[0])) + return "sub%.l %0,%0"; + else if (DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#if defined(MOTOROLA) && !defined(CRDS) + return "moveq%.l %1,%0"; +#else + return "moveq %1,%0"; +#endif + } + else if (INTVAL (operands[1]) < 0x8000 + && INTVAL (operands[1]) >= -0x8000) + return "move%.w %1,%0"; + } + else if (CONSTANT_P (operands[1])) + return "move%.l %1,%0"; +#ifndef SGS_NO_LI + /* Recognize the insn before a tablejump, one that refers + to a table of offsets. Such an insn will need to refer + to a label on the insn. So output one. Use the label-number + of the table of offsets to generate this label. This code, + and similar code below, assumes that there will be at most one + reference to each table. */ + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == LABEL_REF + && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) != PLUS) + { + rtx labelref = XEXP (XEXP (operands[1], 0), 1); +#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES) +#ifdef SGS + asm_fprintf (asm_out_file, "\tset %LLI%d,.+2\n", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#else /* not SGS */ + asm_fprintf (asm_out_file, "\t.set %LLI%d,.+2\n", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#endif /* not SGS */ +#else /* SGS_SWITCH_TABLES or not MOTOROLA */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LI", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#ifdef SGS_SWITCH_TABLES + /* Set flag saying we need to define the symbol + LD%n (with value L%n-LI%n) at the end of the switch table. */ + switch_table_difference_label_flag = 1; +#endif /* SGS_SWITCH_TABLES */ +#endif /* SGS_SWITCH_TABLES or not MOTOROLA */ + } +#endif /* SGS_NO_LI */ + return "move%.w %1,%0"; +} + +char * +output_move_qimode (operands) + rtx *operands; +{ + rtx xoperands[4]; + + /* This is probably useless, since it loses for pushing a struct + of several bytes a byte at a time. */ + /* 68k family always modifies the stack pointer by at least 2, even for + byte pushes. The 5200 (coldfire) does not do this. */ + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC + && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx + && ! ADDRESS_REG_P (operands[1]) + && ! TARGET_5200) + { + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx_MEM (QImode, + gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, const1_rtx)); + /* Just pushing a byte puts it in the high byte of the halfword. */ + /* We must put it in the low-order, high-numbered byte. */ + if (!reg_mentioned_p (stack_pointer_rtx, operands[1])) + { + xoperands[3] = stack_pointer_rtx; +#ifndef NO_ADDSUB_Q + output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands); +#else + output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands); +#endif + } + else + output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands); + return ""; + } + + /* clr and st insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + if (!ADDRESS_REG_P (operands[0]) + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + { + if (operands[1] == const0_rtx) + return "clr%.b %0"; + if ((!TARGET_5200 || DATA_REG_P (operands[0])) + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 255) == 255) + { + CC_STATUS_INIT; + return "st %0"; + } + } + if (GET_CODE (operands[1]) == CONST_INT + && DATA_REG_P (operands[0]) + && INTVAL (operands[1]) < 128 + && INTVAL (operands[1]) >= -128) + { +#if defined(MOTOROLA) && !defined(CRDS) + return "moveq%.l %1,%0"; +#else + return "moveq %1,%0"; +#endif + } + if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0])) + return "sub%.l %0,%0"; + if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) + return "move%.l %1,%0"; + /* 68k family (including the 5200 coldfire) does not support byte moves to + from address registers. */ + if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) + return "move%.w %1,%0"; + return "move%.b %1,%0"; +} + +char * +output_move_stricthi (operands) + rtx *operands; +{ + if (operands[1] == const0_rtx + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + return "clr%.w %0"; + return "move%.w %1,%0"; +} + +char * +output_move_strictqi (operands) + rtx *operands; +{ + if (operands[1] == const0_rtx + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + return "clr%.b %0"; + return "move%.b %1,%0"; +} + +/* Return the best assembler insn template + for moving operands[1] into operands[0] as a fullword. */ + +static char * +singlemove_string (operands) + rtx *operands; +{ +#ifdef SUPPORT_SUN_FPA + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return "fpmoves %1,%0"; +#endif + if (GET_CODE (operands[1]) == CONST_INT) + return output_move_simode_const (operands); + return "move%.l %1,%0"; +} + + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ + +char * +output_move_double (operands) + rtx *operands; +{ + enum + { + REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP + } optype0, optype1; + rtx latehalf[2]; + rtx middlehalf[2]; + rtx xops[2]; + rtx addreg0 = 0, addreg1 = 0; + int dest_overlapped_low = 0; + int size = GET_MODE_SIZE (GET_MODE (operands[0])); + + middlehalf[0] = 0; + middlehalf[1] = 0; + + /* First classify both operands. */ + + if (REG_P (operands[0])) + optype0 = REGOP; + else if (offsettable_memref_p (operands[0])) + optype0 = OFFSOP; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + optype0 = POPOP; + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + optype0 = PUSHOP; + else if (GET_CODE (operands[0]) == MEM) + optype0 = MEMOP; + else + optype0 = RNDOP; + + if (REG_P (operands[1])) + optype1 = REGOP; + else if (CONSTANT_P (operands[1])) + optype1 = CNSTOP; + 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 (XEXP (operands[1], 0)) == PRE_DEC) + optype1 = PUSHOP; + else if (GET_CODE (operands[1]) == MEM) + optype1 = MEMOP; + else + optype1 = RNDOP; + + /* Check for the cases that the operand constraints are not + supposed to allow to happen. Abort if we get one, + because generating code for these cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP) + abort (); + + /* If one operand is decrementing and one is incrementing + decrement the former register explicitly + and change that operand into ordinary indexing. */ + + if (optype0 == PUSHOP && optype1 == POPOP) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); + if (size == 12) + output_asm_insn ("sub%.l %#12,%0", operands); + else + output_asm_insn ("subq%.l %#8,%0", operands); + if (GET_MODE (operands[1]) == XFmode) + operands[0] = gen_rtx_MEM (XFmode, operands[0]); + else if (GET_MODE (operands[0]) == DFmode) + operands[0] = gen_rtx_MEM (DFmode, operands[0]); + else + operands[0] = gen_rtx_MEM (DImode, operands[0]); + optype0 = OFFSOP; + } + if (optype0 == POPOP && optype1 == PUSHOP) + { + operands[1] = XEXP (XEXP (operands[1], 0), 0); + if (size == 12) + output_asm_insn ("sub%.l %#12,%1", operands); + else + output_asm_insn ("subq%.l %#8,%1", operands); + if (GET_MODE (operands[1]) == XFmode) + operands[1] = gen_rtx_MEM (XFmode, operands[1]); + else if (GET_MODE (operands[1]) == DFmode) + operands[1] = gen_rtx_MEM (DFmode, operands[1]); + else + operands[1] = gen_rtx_MEM (DImode, operands[1]); + optype1 = OFFSOP; + } + + /* If an operand is an unoffsettable memory ref, find a register + we can increment temporarily to make it refer to the second word. */ + + if (optype0 == MEMOP) + addreg0 = find_addr_reg (XEXP (operands[0], 0)); + + if (optype1 == MEMOP) + addreg1 = find_addr_reg (XEXP (operands[1], 0)); + + /* Ok, we can do one word at a time. + Normally we do the low-numbered word first, + but if either operand is autodecrementing then we + do the high-numbered word first. + + In either case, set up in LATEHALF the operands to use + for the high-numbered word and in some cases alter the + operands in OPERANDS to be suitable for the low-numbered word. */ + + if (size == 12) + { + if (optype0 == REGOP) + { + latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); + middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + } + else if (optype0 == OFFSOP) + { + middlehalf[0] = adj_offsettable_operand (operands[0], 4); + latehalf[0] = adj_offsettable_operand (operands[0], size - 4); + } + else + { + middlehalf[0] = operands[0]; + latehalf[0] = operands[0]; + } + + if (optype1 == REGOP) + { + latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); + middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + } + else if (optype1 == OFFSOP) + { + middlehalf[1] = adj_offsettable_operand (operands[1], 4); + latehalf[1] = adj_offsettable_operand (operands[1], size - 4); + } + else if (optype1 == CNSTOP) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + REAL_VALUE_TYPE r; + long l[3]; + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); + operands[1] = GEN_INT (l[0]); + middlehalf[1] = GEN_INT (l[1]); + latehalf[1] = GEN_INT (l[2]); + } + else if (CONSTANT_P (operands[1])) + { + /* actually, no non-CONST_DOUBLE constant should ever + appear here. */ + abort (); + if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) + latehalf[1] = constm1_rtx; + else + latehalf[1] = const0_rtx; + } + } + else + { + middlehalf[1] = operands[1]; + latehalf[1] = operands[1]; + } + } + else + /* size is not 12: */ + { + if (optype0 == REGOP) + latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], size - 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], size - 4); + else if (optype1 == CNSTOP) + split_double (operands[1], &operands[1], &latehalf[1]); + else + latehalf[1] = operands[1]; + } + + /* If insn is effectively movd N(sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. */ + if (optype0 == PUSHOP + && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) + operands[1] = middlehalf[1] = latehalf[1]; + + /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), + if the upper part of reg N does not appear in the MEM, arrange to + emit the move late-half first. Otherwise, compute the MEM address + into the upper part of N and use that as a pointer to the memory + operand. */ + if (optype0 == REGOP + && (optype1 == OFFSOP || optype1 == MEMOP)) + { + rtx testlow = gen_rtx_REG (SImode, REGNO (operands[0])); + + if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) + && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + compute the address into latehalf of dest. + Note that this can't happen if the dest is two data regs. */ +compadr: + xops[0] = latehalf[0]; + xops[1] = XEXP (operands[1], 0); + output_asm_insn ("lea %a1,%0", xops); + if( GET_MODE (operands[1]) == XFmode ) + { + operands[1] = gen_rtx_MEM (XFmode, latehalf[0]); + middlehalf[1] = adj_offsettable_operand (operands[1], size-8); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + else + { + operands[1] = gen_rtx_MEM (DImode, latehalf[0]); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + } + else if (size == 12 + && reg_overlap_mentioned_p (middlehalf[0], + XEXP (operands[1], 0))) + { + /* Check for two regs used by both source and dest. + Note that this can't happen if the dest is all data regs. + It can happen if the dest is d6, d7, a0. + But in that case, latehalf is an addr reg, so + the code at compadr does ok. */ + + if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) + || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + goto compadr; + + /* JRV says this can't happen: */ + if (addreg0 || addreg1) + abort (); + + /* Only the middle reg conflicts; simply put it last. */ + output_asm_insn (singlemove_string (operands), operands); + output_asm_insn (singlemove_string (latehalf), latehalf); + output_asm_insn (singlemove_string (middlehalf), middlehalf); + return ""; + } + else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))) + /* If the low half of dest is mentioned in the source memory + address, the arrange to emit the move late half first. */ + dest_overlapped_low = 1; + } + + /* If one or both operands autodecrementing, + do the two words, high-numbered first. */ + + /* Likewise, the first move would clobber the source of the second one, + do them in the other order. This happens only for registers; + such overlap can't happen in memory unless the user explicitly + sets it up, and that is an undefined circumstance. */ + + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) + || REGNO (operands[0]) == REGNO (latehalf[1]))) + || dest_overlapped_low) + { + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + { + if (size == 12) + output_asm_insn ("addq%.l %#8,%0", &addreg0); + else + output_asm_insn ("addq%.l %#4,%0", &addreg0); + } + if (addreg1) + { + if (size == 12) + output_asm_insn ("addq%.l %#8,%0", &addreg1); + else + output_asm_insn ("addq%.l %#4,%0", &addreg1); + } + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + output_asm_insn ("subq%.l %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subq%.l %#4,%0", &addreg1); + + if (size == 12) + { + output_asm_insn (singlemove_string (middlehalf), middlehalf); + if (addreg0) + output_asm_insn ("subq%.l %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("subq%.l %#4,%0", &addreg1); + } + + /* Do low-numbered word. */ + return singlemove_string (operands); + } + + /* Normal case: do the two words, low-numbered first. */ + + output_asm_insn (singlemove_string (operands), operands); + + /* Do the middle one of the three words for long double */ + if (size == 12) + { + if (addreg0) + output_asm_insn ("addq%.l %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addq%.l %#4,%0", &addreg1); + + output_asm_insn (singlemove_string (middlehalf), middlehalf); + } + + /* Make any unoffsettable addresses point at high-numbered word. */ + if (addreg0) + output_asm_insn ("addq%.l %#4,%0", &addreg0); + if (addreg1) + output_asm_insn ("addq%.l %#4,%0", &addreg1); + + /* Do that word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + /* Undo the adds we just did. */ + if (addreg0) + { + if (size == 12) + output_asm_insn ("subq%.l %#8,%0", &addreg0); + else + output_asm_insn ("subq%.l %#4,%0", &addreg0); + } + if (addreg1) + { + if (size == 12) + output_asm_insn ("subq%.l %#8,%0", &addreg1); + else + output_asm_insn ("subq%.l %#4,%0", &addreg1); + } + + return ""; +} + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. */ + +static rtx +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG) + return addr; + abort (); +} + +/* Output assembler code to perform a 32 bit 3 operand add. */ + +char * +output_addsi3 (operands) + rtx *operands; +{ + if (! operands_match_p (operands[0], operands[1])) + { + if (!ADDRESS_REG_P (operands[1])) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + + /* These insns can result from reloads to access + stack slots over 64k from the frame pointer. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) + 0x8000 >= (unsigned) 0x10000) + return "move%.l %2,%0\n\tadd%.l %1,%0"; +#ifdef SGS + if (GET_CODE (operands[2]) == REG) + return "lea 0(%1,%2.l),%0"; + else + return "lea %c2(%1),%0"; +#else /* not SGS */ +#ifdef MOTOROLA + if (GET_CODE (operands[2]) == REG) + return "lea (%1,%2.l),%0"; + else + return "lea (%c2,%1),%0"; +#else /* not MOTOROLA (MIT syntax) */ + if (GET_CODE (operands[2]) == REG) + return "lea %1@(0,%2:l),%0"; + else + return "lea %1@(%c2),%0"; +#endif /* not MOTOROLA */ +#endif /* not SGS */ + } + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return "addq%.l %2,%0"; + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "subq%.l %2,%0"; + } + /* On the CPU32 it is faster to use two addql instructions to + add a small integer (8 < N <= 16) to a register. + Likewise for subql. */ + if (TARGET_CPU32 && REG_P (operands[0])) + { + if (INTVAL (operands[2]) > 8 + && INTVAL (operands[2]) <= 16) + { + operands[2] = GEN_INT (INTVAL (operands[2]) - 8); + return "addq%.l %#8,%0\n\taddq%.l %2,%0"; + } + if (INTVAL (operands[2]) < -8 + && INTVAL (operands[2]) >= -16) + { + operands[2] = GEN_INT (-INTVAL (operands[2]) - 8); + return "subq%.l %#8,%0\n\tsubq%.l %2,%0"; + } + } +#endif + if (ADDRESS_REG_P (operands[0]) + && INTVAL (operands[2]) >= -0x8000 + && INTVAL (operands[2]) < 0x8000) + { + if (TARGET_68040) + return "add%.w %2,%0"; + else +#ifdef MOTOROLA + return "lea (%c2,%0),%0"; +#else + return "lea %0@(%c2),%0"; +#endif + } + } + return "add%.l %2,%0"; +} + +/* Store in cc_status the expressions that the condition codes will + describe after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register fail to + set the cc's. However, in some cases these instructions can make it + possibly invalid to use the saved cc's. In those cases we clear out + some or all of the saved cc's so they won't be used. */ + +void +notice_update_cc (exp, insn) + rtx exp; + rtx insn; +{ + /* If the cc is being set from the fpa and the expression is not an + explicit floating point test instruction (which has code to deal with + this), reinit the CC. */ + if (((cc_status.value1 && FPA_REG_P (cc_status.value1)) + || (cc_status.value2 && FPA_REG_P (cc_status.value2))) + && !(GET_CODE (exp) == PARALLEL + && GET_CODE (XVECEXP (exp, 0, 0)) == SET + && XEXP (XVECEXP (exp, 0, 0), 0) == cc0_rtx)) + { + CC_STATUS_INIT; + } + else if (GET_CODE (exp) == SET) + { + if (GET_CODE (SET_SRC (exp)) == CALL) + { + CC_STATUS_INIT; + } + else if (ADDRESS_REG_P (SET_DEST (exp))) + { + if (cc_status.value1 && modified_in_p (cc_status.value1, insn)) + cc_status.value1 = 0; + if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) + cc_status.value2 = 0; + } + else if (!FP_REG_P (SET_DEST (exp)) + && SET_DEST (exp) != cc0_rtx + && (FP_REG_P (SET_SRC (exp)) + || GET_CODE (SET_SRC (exp)) == FIX + || GET_CODE (SET_SRC (exp)) == FLOAT_TRUNCATE + || GET_CODE (SET_SRC (exp)) == FLOAT_EXTEND)) + { + CC_STATUS_INIT; + } + /* A pair of move insns doesn't produce a useful overall cc. */ + else if (!FP_REG_P (SET_DEST (exp)) + && !FP_REG_P (SET_SRC (exp)) + && GET_MODE_SIZE (GET_MODE (SET_SRC (exp))) > 4 + && (GET_CODE (SET_SRC (exp)) == REG + || GET_CODE (SET_SRC (exp)) == MEM + || GET_CODE (SET_SRC (exp)) == CONST_DOUBLE)) + { + CC_STATUS_INIT; + } + else if (GET_CODE (SET_SRC (exp)) == CALL) + { + CC_STATUS_INIT; + } + else if (XEXP (exp, 0) != pc_rtx) + { + cc_status.flags = 0; + cc_status.value1 = XEXP (exp, 0); + cc_status.value2 = XEXP (exp, 1); + } + } + else if (GET_CODE (exp) == PARALLEL + && GET_CODE (XVECEXP (exp, 0, 0)) == SET) + { + if (ADDRESS_REG_P (XEXP (XVECEXP (exp, 0, 0), 0))) + CC_STATUS_INIT; + else if (XEXP (XVECEXP (exp, 0, 0), 0) != pc_rtx) + { + cc_status.flags = 0; + cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0); + cc_status.value2 = XEXP (XVECEXP (exp, 0, 0), 1); + } + } + else + CC_STATUS_INIT; + if (cc_status.value2 != 0 + && ADDRESS_REG_P (cc_status.value2) + && GET_MODE (cc_status.value2) == QImode) + CC_STATUS_INIT; + if (cc_status.value2 != 0 + && !(cc_status.value1 && FPA_REG_P (cc_status.value1))) + switch (GET_CODE (cc_status.value2)) + { + case PLUS: case MINUS: case MULT: + case DIV: case UDIV: case MOD: case UMOD: case NEG: +#if 0 /* These instructions always clear the overflow bit */ + case ASHIFT: case ASHIFTRT: case LSHIFTRT: + case ROTATE: case ROTATERT: +#endif + if (GET_MODE (cc_status.value2) != VOIDmode) + cc_status.flags |= CC_NO_OVERFLOW; + break; + case ZERO_EXTEND: + /* (SET r1 (ZERO_EXTEND r2)) on this machine + ends with a move insn moving r2 in r2's mode. + Thus, the cc's are set for r2. + This can set N bit spuriously. */ + cc_status.flags |= CC_NOT_NEGATIVE; + + default: + break; + } + 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 && FP_REG_P (cc_status.value1)) + || (cc_status.value2 && FP_REG_P (cc_status.value2))) + && !((cc_status.value1 && FPA_REG_P (cc_status.value1)) + || (cc_status.value2 && FPA_REG_P (cc_status.value2)))) + cc_status.flags = CC_IN_68881; +} + +char * +output_move_const_double (operands) + rtx *operands; +{ +#ifdef SUPPORT_SUN_FPA + if (TARGET_FPA && FPA_REG_P (operands[0])) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.d %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.d %1,%0"; + } + else +#endif + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.d %1,%0"; + } +} + +char * +output_move_const_single (operands) + rtx *operands; +{ +#ifdef SUPPORT_SUN_FPA + if (TARGET_FPA) + { + int code = standard_sun_fpa_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fpmove%%.s %%%%%d,%%0", code & 0x1ff); + return buf; + } + return "fpmove%.s %1,%0"; + } + else +#endif /* defined SUPPORT_SUN_FPA */ + { + int code = standard_68881_constant_p (operands[1]); + + if (code != 0) + { + static char buf[40]; + + sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff); + return buf; + } + return "fmove%.s %f1,%0"; + } +} + +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the "fmovecr" instruction. + The value, anded with 0xff, gives the code to use in fmovecr + to get the desired constant. */ + +/* This code has been fixed for cross-compilation. */ + +static int inited_68881_table = 0; + +char *strings_68881[7] = { + "0.0", + "1.0", + "10.0", + "100.0", + "10000.0", + "1e8", + "1e16" + }; + +int codes_68881[7] = { + 0x0f, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37 + }; + +REAL_VALUE_TYPE values_68881[7]; + +/* Set up values_68881 array by converting the decimal values + strings_68881 to binary. */ + +void +init_68881_table () +{ + int i; + REAL_VALUE_TYPE r; + enum machine_mode mode; + + mode = SFmode; + for (i = 0; i < 7; i++) + { + if (i == 6) + mode = DFmode; + r = REAL_VALUE_ATOF (strings_68881[i], mode); + values_68881[i] = r; + } + inited_68881_table = 1; +} + +int +standard_68881_constant_p (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + +#ifdef NO_ASM_FMOVECR + return 0; +#endif + + /* fmovecr must be emulated on the 68040 and 68060, so it shouldn't be + used at all on those chips. */ + if (TARGET_68040 || TARGET_68060) + return 0; + +#ifndef REAL_ARITHMETIC +#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT + if (! flag_pretend_float) + return 0; +#endif +#endif + + if (! inited_68881_table) + init_68881_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + + for (i = 0; i < 6; i++) + { + if (REAL_VALUES_EQUAL (r, values_68881[i])) + return (codes_68881[i]); + } + + if (GET_MODE (x) == SFmode) + return 0; + + if (REAL_VALUES_EQUAL (r, values_68881[6])) + return (codes_68881[6]); + + /* larger powers of ten in the constants ram are not used + because they are not equal to a `double' C constant. */ + return 0; +} + +/* If X is a floating-point constant, return the logarithm of X base 2, + or 0 if X is not a power of 2. */ + +int +floating_exact_log2 (x) + rtx x; +{ + REAL_VALUE_TYPE r, r1; + int i; + +#ifndef REAL_ARITHMETIC +#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT + if (! flag_pretend_float) + return 0; +#endif +#endif + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + + if (REAL_VALUES_LESS (r, dconst0)) + return 0; + + r1 = dconst1; + i = 0; + while (REAL_VALUES_LESS (r1, r)) + { + r1 = REAL_VALUE_LDEXP (dconst1, i); + if (REAL_VALUES_EQUAL (r1, r)) + return i; + i = i + 1; + } + return 0; +} + +#ifdef SUPPORT_SUN_FPA +/* Return nonzero if X, a CONST_DOUBLE, has a value that we can get + from the Sun FPA's constant RAM. + The value returned, anded with 0x1ff, gives the code to use in fpmove + to get the desired constant. */ + +static int inited_FPA_table = 0; + +char *strings_FPA[38] = { +/* small rationals */ + "0.0", + "1.0", + "0.5", + "-1.0", + "2.0", + "3.0", + "4.0", + "8.0", + "0.25", + "0.125", + "10.0", + "-0.5", +/* Decimal equivalents of double precision values */ + "2.718281828459045091", /* D_E */ + "6.283185307179586477", /* 2 pi */ + "3.141592653589793116", /* D_PI */ + "1.570796326794896619", /* pi/2 */ + "1.414213562373095145", /* D_SQRT2 */ + "0.7071067811865475244", /* 1/sqrt(2) */ + "-1.570796326794896619", /* -pi/2 */ + "1.442695040888963387", /* D_LOG2ofE */ + "3.321928024887362182", /* D_LOG2of10 */ + "0.6931471805599452862", /* D_LOGEof2 */ + "2.302585092994045901", /* D_LOGEof10 */ + "0.3010299956639811980", /* D_LOG10of2 */ + "0.4342944819032518167", /* D_LOG10ofE */ +/* Decimal equivalents of single precision values */ + "2.718281745910644531", /* S_E */ + "6.283185307179586477", /* 2 pi */ + "3.141592741012573242", /* S_PI */ + "1.570796326794896619", /* pi/2 */ + "1.414213538169860840", /* S_SQRT2 */ + "0.7071067811865475244", /* 1/sqrt(2) */ + "-1.570796326794896619", /* -pi/2 */ + "1.442695021629333496", /* S_LOG2ofE */ + "3.321928024291992188", /* S_LOG2of10 */ + "0.6931471824645996094", /* S_LOGEof2 */ + "2.302585124969482442", /* S_LOGEof10 */ + "0.3010300099849700928", /* S_LOG10of2 */ + "0.4342944920063018799", /* S_LOG10ofE */ +}; + + +int codes_FPA[38] = { +/* small rationals */ + 0x200, + 0xe, + 0xf, + 0x10, + 0x11, + 0xb1, + 0x12, + 0x13, + 0x15, + 0x16, + 0x17, + 0x2e, +/* double precision */ + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0x27, + 0x28, + 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d, +/* single precision */ + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0x27, + 0x28, + 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d + }; + +REAL_VALUE_TYPE values_FPA[38]; + +/* This code has been fixed for cross-compilation. */ + +void +init_FPA_table () +{ + enum machine_mode mode; + int i; + REAL_VALUE_TYPE r; + + mode = DFmode; + for (i = 0; i < 38; i++) + { + if (i == 25) + mode = SFmode; + r = REAL_VALUE_ATOF (strings_FPA[i], mode); + values_FPA[i] = r; + } + inited_FPA_table = 1; +} + + +int +standard_sun_fpa_constant_p (x) + rtx x; +{ + REAL_VALUE_TYPE r; + int i; + +#ifndef REAL_ARITHMETIC +#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT + if (! flag_pretend_float) + return 0; +#endif +#endif + + if (! inited_FPA_table) + init_FPA_table (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + + for (i=0; i<12; i++) + { + if (REAL_VALUES_EQUAL (r, values_FPA[i])) + return (codes_FPA[i]); + } + + if (GET_MODE (x) == SFmode) + { + for (i=25; i<38; i++) + { + if (REAL_VALUES_EQUAL (r, values_FPA[i])) + return (codes_FPA[i]); + } + } + else + { + for (i=12; i<25; i++) + { + if (REAL_VALUES_EQUAL (r, values_FPA[i])) + return (codes_FPA[i]); + } + } + return 0x0; +} +#endif /* define SUPPORT_SUN_FPA */ + +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand X. X is an RTL + expression. + + CODE is a value that can be used to specify one of several ways + of printing the operand. It is used when identical operands + must be printed differently depending on the context. CODE + comes from the `%' specification that was used to request + printing of the operand. If the specification was just `%DIGIT' + then CODE is 0; if the specification was `%LTR DIGIT' then CODE + is the ASCII code for LTR. + + If X is a register, this macro should print the register's name. + The names can be found in an array `reg_names' whose type is + `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. + + When the machine description has a specification `%PUNCT' (a `%' + followed by a punctuation character), this macro is called with + a null pointer for X and the punctuation character for CODE. + + The m68k specific codes are: + + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax, $ in CRDS/UNOS syntax). + '!' for the cc register (used in an `and to cc' insn). + '$' for the letter `s' in an op code, but only on the 68040. + '&' for the letter `d' in an op code, but only on the 68040. + '/' for register prefix needed by longlong.h. + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather + than directly). Second part of 'y' below. + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. + 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs + CONST_DOUBLE's as SunFPA constant RAM registers if + possible, so it should not be used except for the SunFPA. + + */ + +void +print_operand (file, op, letter) + FILE *file; /* file to write to */ + rtx op; /* operand to print */ + int letter; /* %<letter> or 0 */ +{ +#ifdef SUPPORT_SUN_FPA + int i; +#endif + + if (letter == '.') + { +#if defined (MOTOROLA) && !defined (CRDS) + asm_fprintf (file, "."); +#endif + } + else if (letter == '#') + { + asm_fprintf (file, "%0I"); + } + else if (letter == '-') + { +#ifdef MOTOROLA + asm_fprintf (file, "-(%Rsp)"); +#else + asm_fprintf (file, "%Rsp@-"); +#endif + } + else if (letter == '+') + { +#ifdef MOTOROLA + asm_fprintf (file, "(%Rsp)+"); +#else + asm_fprintf (file, "%Rsp@+"); +#endif + } + else if (letter == '@') + { +#ifdef MOTOROLA + asm_fprintf (file, "(%Rsp)"); +#else + asm_fprintf (file, "%Rsp@"); +#endif + } + else if (letter == '!') + { + asm_fprintf (file, "%Rfpcr"); + } + else if (letter == '$') + { + if (TARGET_68040_ONLY) + { + fprintf (file, "s"); + } + } + else if (letter == '&') + { + if (TARGET_68040_ONLY) + { + fprintf (file, "d"); + } + } + else if (letter == '/') + { + asm_fprintf (file, "%R"); + } + else if (GET_CODE (op) == REG) + { +#ifdef SUPPORT_SUN_FPA + if (REGNO (op) < 16 + && (letter == 'y' || letter == 'x') + && GET_MODE (op) == DFmode) + { + fprintf (file, "%s:%s", reg_names[REGNO (op)], + reg_names[REGNO (op)+1]); + } + else +#endif + { + if (letter == 'R') + /* Print out the second register name of a register pair. + I.e., R (6) => 7. */ + fputs (reg_names[REGNO (op) + 1], file); + else + fputs (reg_names[REGNO (op)], file); + } + } + else if (GET_CODE (op) == MEM) + { + output_address (XEXP (op, 0)); + if (letter == 'd' && ! TARGET_68020 + && CONSTANT_ADDRESS_P (XEXP (op, 0)) + && !(GET_CODE (XEXP (op, 0)) == CONST_INT + && INTVAL (XEXP (op, 0)) < 0x8000 + && INTVAL (XEXP (op, 0)) >= -0x8000)) + { +#ifdef MOTOROLA + fprintf (file, ".l"); +#else + fprintf (file, ":l"); +#endif + } + } +#ifdef SUPPORT_SUN_FPA + else if ((letter == 'y' || letter == 'w') + && GET_CODE (op) == CONST_DOUBLE + && (i = standard_sun_fpa_constant_p (op))) + { + fprintf (file, "%%%d", i & 0x1ff); + } +#endif + else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode) + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + ASM_OUTPUT_FLOAT_OPERAND (letter, file, r); + } + else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode) + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r); + } + else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode) + { + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + ASM_OUTPUT_DOUBLE_OPERAND (file, r); + } + else + { + asm_fprintf (file, "%0I"); output_addr_const (file, op); + } +} + + +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand that is a memory + reference whose address is ADDR. ADDR is an RTL expression. + + Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) when not generating + PIC code is in the insn before a tablejump, and we know that m68k.md + generates a label LInnn: on such an insn. + + It is possible for PIC to generate a (plus (label_ref...) (reg...)) + and we handle that just like we would a (plus (symbol_ref...) (reg...)). + + Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" + fails to assemble. Luckily "Lnnn(pc,d0.l*2)" produces the results + we want. This difference can be accommodated by using an assembler + define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other + string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END + macro. See m68k/sgs.h for an example; for versions without the bug. + Some assemblers refuse all the above solutions. The workaround is to + emit "K(pc,d0.l*2)" with K being a small constant known to give the + right behaviour. + + They also do not like things like "pea 1.w", so we simple leave off + the .w on small constants. + + This routine is responsible for distinguishing between -fpic and -fPIC + style relocations in an address. When generating -fpic code the + offset is output in word mode (eg movel a5@(_foo:w), a0). When generating + -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */ + +#ifndef ASM_OUTPUT_CASE_FETCH +#ifdef MOTOROLA +#ifdef SGS +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname) +#else +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname) +#endif +#else +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname) +#endif +#endif /* ASM_OUTPUT_CASE_FETCH */ + +void +print_operand_address (file, addr) + FILE *file; + rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + switch (GET_CODE (addr)) + { + case REG: +#ifdef MOTOROLA + fprintf (file, "(%s)", reg_names[REGNO (addr)]); +#else + fprintf (file, "%s@", reg_names[REGNO (addr)]); +#endif + break; + case PRE_DEC: +#ifdef MOTOROLA + fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); +#else + fprintf (file, "%s@-", reg_names[REGNO (XEXP (addr, 0))]); +#endif + break; + case POST_INC: +#ifdef MOTOROLA + fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); +#else + fprintf (file, "%s@+", reg_names[REGNO (XEXP (addr, 0))]); +#endif + break; + case PLUS: + reg1 = reg2 = ireg = breg = offset = 0; + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) + { + offset = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) + { + offset = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + if (GET_CODE (addr) != PLUS) + { + ; + } + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) + { + reg1 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) + { + reg1 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + 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 + || GET_CODE (addr) == SIGN_EXTEND) + { + if (reg1 == 0) + { + reg1 = addr; + } + else + { + reg2 = addr; + } + addr = 0; + } +#if 0 /* for OLD_INDEXING */ + else if (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG) + { + reg2 = XEXP (addr, 0); + addr = XEXP (addr, 1); + } + else if (GET_CODE (XEXP (addr, 1)) == REG) + { + reg2 = XEXP (addr, 1); + addr = XEXP (addr, 0); + } + } +#endif + if (offset != 0) + { + if (addr != 0) + { + abort (); + } + addr = offset; + } + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND + || GET_CODE (reg1) == MULT)) + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) + { + breg = reg2; + ireg = reg1; + } + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) + { + breg = reg1; + ireg = reg2; + } + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF + && ! (flag_pic && ireg == pic_offset_table_rtx)) + { + int scale = 1; + if (GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)); + ireg = XEXP (ireg, 0); + } + if (GET_CODE (ireg) == SIGN_EXTEND) + { + ASM_OUTPUT_CASE_FETCH (file, + CODE_LABEL_NUMBER (XEXP (addr, 0)), + reg_names[REGNO (XEXP (ireg, 0))]); + fprintf (file, "w"); + } + else + { + ASM_OUTPUT_CASE_FETCH (file, + CODE_LABEL_NUMBER (XEXP (addr, 0)), + reg_names[REGNO (ireg)]); + fprintf (file, "l"); + } + if (scale != 1) + { +#ifdef MOTOROLA + fprintf (file, "*%d", scale); +#else + fprintf (file, ":%d", scale); +#endif + } + putc (')', file); + break; + } + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF + && ! (flag_pic && breg == pic_offset_table_rtx)) + { + ASM_OUTPUT_CASE_FETCH (file, + CODE_LABEL_NUMBER (XEXP (addr, 0)), + reg_names[REGNO (breg)]); + fprintf (file, "l)"); + break; + } + if (ireg != 0 || breg != 0) + { + int scale = 1; + if (breg == 0) + { + abort (); + } + if (! flag_pic && addr && GET_CODE (addr) == LABEL_REF) + { + abort (); + } +#ifdef MOTOROLA + if (addr != 0) + { + output_addr_const (file, addr); + if (flag_pic && (breg == pic_offset_table_rtx)) + { + fprintf (file, "@GOT"); + if (flag_pic == 1) + fprintf (file, ".w"); + } + } + fprintf (file, "(%s", reg_names[REGNO (breg)]); + if (ireg != 0) + { + putc (',', file); + } +#else + fprintf (file, "%s@(", reg_names[REGNO (breg)]); + if (addr != 0) + { + output_addr_const (file, addr); + if ((flag_pic == 1) && (breg == pic_offset_table_rtx)) + fprintf (file, ":w"); + if ((flag_pic == 2) && (breg == pic_offset_table_rtx)) + fprintf (file, ":l"); + } + if (addr != 0 && ireg != 0) + { + putc (',', file); + } +#endif + if (ireg != 0 && GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)); + ireg = XEXP (ireg, 0); + } + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) + { +#ifdef MOTOROLA + fprintf (file, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); +#else + fprintf (file, "%s:w", reg_names[REGNO (XEXP (ireg, 0))]); +#endif + } + else if (ireg != 0) + { +#ifdef MOTOROLA + fprintf (file, "%s.l", reg_names[REGNO (ireg)]); +#else + fprintf (file, "%s:l", reg_names[REGNO (ireg)]); +#endif + } + if (scale != 1) + { +#ifdef MOTOROLA + fprintf (file, "*%d", scale); +#else + fprintf (file, ":%d", scale); +#endif + } + putc (')', file); + break; + } + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF + && ! (flag_pic && reg1 == pic_offset_table_rtx)) + { + ASM_OUTPUT_CASE_FETCH (file, + CODE_LABEL_NUMBER (XEXP (addr, 0)), + reg_names[REGNO (reg1)]); + fprintf (file, "l)"); + break; + } + /* FALL-THROUGH (is this really what we want? */ + default: + if (GET_CODE (addr) == CONST_INT + && INTVAL (addr) < 0x8000 + && INTVAL (addr) >= -0x8000) + { +#ifdef MOTOROLA +#ifdef SGS + /* Many SGS assemblers croak on size specifiers for constants. */ + fprintf (file, "%d", INTVAL (addr)); +#else + fprintf (file, "%d.w", INTVAL (addr)); +#endif +#else + fprintf (file, "%d:w", INTVAL (addr)); +#endif + } + else + { + output_addr_const (file, addr); + } + break; + } +} + +/* Check for cases where a clr insns can be omitted from code using + strict_low_part sets. For example, the second clrl here is not needed: + clrl d0; movw a0@+,d0; use d0; clrl d0; movw a0@+; use d0; ... + + MODE is the mode of this STRICT_LOW_PART set. FIRST_INSN is the clear + insn we are checking for redundancy. TARGET is the register set by the + clear insn. */ + +int +strict_low_part_peephole_ok (mode, first_insn, target) + enum machine_mode mode; + rtx first_insn; + rtx target; +{ + rtx p; + + p = prev_nonnote_insn (first_insn); + + while (p) + { + /* If it isn't an insn, then give up. */ + if (GET_CODE (p) != INSN) + return 0; + + if (reg_set_p (target, p)) + { + rtx set = single_set (p); + rtx dest; + + /* If it isn't an easy to recognize insn, then give up. */ + if (! set) + return 0; + + dest = SET_DEST (set); + + /* If this sets the entire target register to zero, then our + first_insn is redundant. */ + if (rtx_equal_p (dest, target) + && SET_SRC (set) == const0_rtx) + return 1; + else if (GET_CODE (dest) == STRICT_LOW_PART + && GET_CODE (XEXP (dest, 0)) == REG + && REGNO (XEXP (dest, 0)) == REGNO (target) + && (GET_MODE_SIZE (GET_MODE (XEXP (dest, 0))) + <= GET_MODE_SIZE (mode))) + /* This is a strict low part set which modifies less than + we are using, so it is safe. */ + ; + else + return 0; + } + + p = prev_nonnote_insn (p); + + } + + return 0; +} + +/* Accept integer operands in the range 0..0xffffffff. We have to check the + range carefully since this predicate is used in DImode contexts. Also, we + need some extra crud to make it work when hosted on 64-bit machines. */ + +int +const_uint32_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ +#if HOST_BITS_PER_WIDE_INT > 32 + /* All allowed constants will fit a CONST_INT. */ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL)); +#else + return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) + || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0)); +#endif +} + +/* Accept integer operands in the range -0x80000000..0x7fffffff. We have + to check the range carefully since this predicate is used in DImode + contexts. */ + +int +const_sint32_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + /* All allowed constants will fit a CONST_INT. */ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); +} + +char * +output_andsi3 (operands) + rtx *operands; +{ + int logval; + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) | 0xffff) == 0xffffffff + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0])) + && !TARGET_5200) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (operands[2] == const0_rtx) + return "clr%.w %0"; + return "and%.w %2,%0"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (~ INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + { + operands[1] = GEN_INT (logval); + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = GEN_INT (logval % 8); + } + /* This does not set condition codes in a standard way. */ + CC_STATUS_INIT; + return "bclr %1,%0"; + } + return "and%.l %2,%0"; +} + +char * +output_iorsi3 (operands) + rtx *operands; +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0])) + && !TARGET_5200) + { + if (GET_CODE (operands[0]) != REG) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (INTVAL (operands[2]) == 0xffff) + return "mov%.w %2,%0"; + return "or%.w %2,%0"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + { + operands[1] = GEN_INT (logval); + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = GEN_INT (logval % 8); + } + CC_STATUS_INIT; + return "bset %1,%0"; + } + return "or%.l %2,%0"; +} + +char * +output_xorsi3 (operands) + rtx *operands; +{ + register int logval; + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) >> 16 == 0 + && (offsettable_memref_p (operands[0]) || DATA_REG_P (operands[0])) + && !TARGET_5200) + { + if (! DATA_REG_P (operands[0])) + operands[0] = adj_offsettable_operand (operands[0], 2); + /* Do not delete a following tstl %0 insn; that would be incorrect. */ + CC_STATUS_INIT; + if (INTVAL (operands[2]) == 0xffff) + return "not%.w %0"; + return "eor%.w %2,%0"; + } + if (GET_CODE (operands[2]) == CONST_INT + && (logval = exact_log2 (INTVAL (operands[2]))) >= 0 + && (DATA_REG_P (operands[0]) + || offsettable_memref_p (operands[0]))) + { + if (DATA_REG_P (operands[0])) + { + operands[1] = GEN_INT (logval); + } + else + { + operands[0] = adj_offsettable_operand (operands[0], 3 - (logval / 8)); + operands[1] = GEN_INT (logval % 8); + } + CC_STATUS_INIT; + return "bchg %1,%0"; + } + return "eor%.l %2,%0"; +} diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h new file mode 100755 index 0000000..4531908 --- /dev/null +++ b/gcc/config/m68k/m68k.h @@ -0,0 +1,2139 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 88, 93-98, 1999 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. */ + + +/* Note that some other tm.h files include this one and then override + many of the definitions that relate to assembler syntax. */ + + +/* Names to predefine in the preprocessor for this target machine. */ + +/* See sun3.h, sun2.h, isi.h for different CPP_PREDEFINES. */ + +/* Print subsidiary information on the compiler version in use. */ +#ifdef MOTOROLA +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola syntax)"); +#else +#define TARGET_VERSION fprintf (stderr, " (68k, MIT syntax)"); +#endif + +/* Define SUPPORT_SUN_FPA to include support for generating code for + the Sun Floating Point Accelerator, an optional product for Sun 3 + machines. By default, it is not defined. Avoid defining it unless + you need to output code for the Sun3+FPA architecture, as it has the + effect of slowing down the register set operations in hard-reg-set.h + (total number of registers will exceed number of bits in a long, + if defined, causing the set operations to expand to loops). + SUPPORT_SUN_FPA is typically defined in sun3.h. */ + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* Compile for a 68020 (not a 68000 or 68010). */ +#define MASK_68020 1 +#define TARGET_68020 (target_flags & MASK_68020) + +/* Compile 68881 insns for floating point (not library calls). */ +#define MASK_68881 2 +#define TARGET_68881 (target_flags & MASK_68881) + +/* Compile using 68020 bitfield insns. */ +#define MASK_BITFIELD 4 +#define TARGET_BITFIELD (target_flags & MASK_BITFIELD) + +/* Compile using rtd insn calling sequence. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define MASK_RTD 8 +#define TARGET_RTD (target_flags & MASK_RTD) + +/* Compile passing first two args in regs 0 and 1. + This exists only to test compiler features that will + be needed for RISC chips. It is not usable + and is not intended to be usable on this cpu. */ +#define MASK_REGPARM 16 +#define TARGET_REGPARM (target_flags & MASK_REGPARM) + +/* Compile with 16-bit `int'. */ +#define MASK_SHORT 32 +#define TARGET_SHORT (target_flags & MASK_SHORT) + +/* Compile with special insns for Sun FPA. */ +#define MASK_FPA 64 +#define TARGET_FPA (target_flags & MASK_FPA) + +/* Compile (actually, link) for Sun SKY board. */ +#define MASK_SKY 128 +#define TARGET_SKY (target_flags & MASK_SKY) + +/* Optimize for 68040, but still allow execution on 68020 + (-m68020-40 or -m68040). + The 68040 will execute all 68030 and 68881/2 instructions, but some + of them must be emulated in software by the OS. When TARGET_68040 is + turned on, these instructions won't be used. This code will still + run on a 68030 and 68881/2. */ +#define MASK_68040 256 +#define TARGET_68040 (target_flags & MASK_68040) + +/* Use the 68040-only fp instructions (-m68040 or -m68060). */ +#define MASK_68040_ONLY 512 +#define TARGET_68040_ONLY (target_flags & MASK_68040_ONLY) + +/* Optimize for 68060, but still allow execution on 68020 + (-m68020-60 or -m68060). + The 68060 will execute all 68030 and 68881/2 instructions, but some + of them must be emulated in software by the OS. When TARGET_68060 is + turned on, these instructions won't be used. This code will still + run on a 68030 and 68881/2. */ +#define MASK_68060 1024 +#define TARGET_68060 (target_flags & MASK_68060) + +/* Compile for mcf5200 */ +#define MASK_5200 2048 +#define TARGET_5200 (target_flags & MASK_5200) + +/* Align ints to a word boundary. This breaks compatibility with the + published ABI's for structures containing ints, but produces faster + code on cpus with 32 bit busses (020, 030, 040, 060, CPU32+, coldfire). + It's required for coldfire cpus without a misalignment module. */ +#define MASK_ALIGN_INT 4096 +#define TARGET_ALIGN_INT (target_flags & MASK_ALIGN_INT) + +/* Compile for a CPU32 */ + /* A 68020 without bitfields is a good heuristic for a CPU32 */ +#define TARGET_CPU32 (TARGET_68020 && !TARGET_BITFIELD) + +/* Macro to define tables used to set the flags. + This is a list in braces of pairs in braces, + each pair being { "NAME", VALUE } + where VALUE is the bits to set or minus the bits to clear. + An empty string NAME is used to identify the default VALUE. */ + +#define TARGET_SWITCHES \ + { { "68020", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY)}, \ + { "c68020", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY)}, \ + { "68020", (MASK_68020|MASK_BITFIELD)}, \ + { "c68020", (MASK_68020|MASK_BITFIELD)}, \ + { "68000", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY \ + |MASK_68020|MASK_BITFIELD|MASK_68881)}, \ + { "c68000", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY \ + |MASK_68020|MASK_BITFIELD|MASK_68881)}, \ + { "bitfield", MASK_BITFIELD}, \ + { "nobitfield", - MASK_BITFIELD}, \ + { "rtd", MASK_RTD}, \ + { "nortd", - MASK_RTD}, \ + { "short", MASK_SHORT}, \ + { "noshort", - MASK_SHORT}, \ + { "fpa", -(MASK_SKY|MASK_68040_ONLY|MASK_68881)}, \ + { "fpa", MASK_FPA}, \ + { "nofpa", - MASK_FPA}, \ + { "sky", -(MASK_FPA|MASK_68040_ONLY|MASK_68881)}, \ + { "sky", MASK_SKY}, \ + { "nosky", - MASK_SKY}, \ + { "68881", - (MASK_FPA|MASK_SKY)}, \ + { "68881", MASK_68881}, \ + { "soft-float", - (MASK_FPA|MASK_SKY|MASK_68040_ONLY|MASK_68881)}, \ + { "68020-40", -(MASK_5200|MASK_68060|MASK_68040_ONLY)}, \ + { "68020-40", (MASK_BITFIELD|MASK_68881|MASK_68020|MASK_68040)}, \ + { "68020-60", -(MASK_5200|MASK_68040_ONLY)}, \ + { "68020-60", (MASK_BITFIELD|MASK_68881|MASK_68020|MASK_68040 \ + |MASK_68060)}, \ + { "68030", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY)}, \ + { "68030", (MASK_68020|MASK_BITFIELD)}, \ + { "68040", - (MASK_5200|MASK_68060)}, \ + { "68040", (MASK_68020|MASK_68881|MASK_BITFIELD \ + |MASK_68040_ONLY|MASK_68040)}, \ + { "68060", - (MASK_5200|MASK_68040)}, \ + { "68060", (MASK_68020|MASK_68881|MASK_BITFIELD \ + |MASK_68040_ONLY|MASK_68060)}, \ + { "5200", - (MASK_68060|MASK_68040|MASK_68040_ONLY|MASK_68020 \ + |MASK_BITFIELD|MASK_68881)}, \ + { "5200", (MASK_5200)}, \ + { "68851", 0}, \ + { "no-68851", 0}, \ + { "68302", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY \ + |MASK_68020|MASK_BITFIELD|MASK_68881)}, \ + { "68332", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY \ + |MASK_BITFIELD|MASK_68881)}, \ + { "68332", MASK_68020}, \ + { "cpu32", - (MASK_5200|MASK_68060|MASK_68040|MASK_68040_ONLY \ + |MASK_BITFIELD|MASK_68881)}, \ + { "cpu32", MASK_68020}, \ + { "align-int", MASK_ALIGN_INT }, \ + { "no-align-int", -MASK_ALIGN_INT }, \ + SUBTARGET_SWITCHES \ + { "", TARGET_DEFAULT}} +/* TARGET_DEFAULT is defined in sun*.h and isi.h, etc. */ + +/* This macro is similar to `TARGET_SWITCHES' but defines names of + command options that have values. Its definition is an + initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + fixed part of the option name, and the address of a variable. The + variable, type `char *', is set to the variable part of the given + option if the fixed part matches. The actual option name is made + by appending `-m' to the specified name. */ +#define TARGET_OPTIONS \ +{ { "align-loops=", &m68k_align_loops_string }, \ + { "align-jumps=", &m68k_align_jumps_string }, \ + { "align-functions=", &m68k_align_funcs_string }, \ + SUBTARGET_OPTIONS \ +} + +/* Sometimes certain combinations of command options do not make + sense on a particular target machine. You can define a macro + `OVERRIDE_OPTIONS' to take account of this. This macro, if + defined, is executed once just after all the command options have + been parsed. + + Don't use this macro to turn on various extra optimizations for + `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ + +#define OVERRIDE_OPTIONS \ +{ \ + override_options(); \ + if (! TARGET_68020 && flag_pic == 2) \ + error("-fPIC is not currently supported on the 68000 or 68010\n"); \ + SUBTARGET_OVERRIDE_OPTIONS; \ +} + +/* These are meant to be redefined in the host dependent files */ +#define SUBTARGET_SWITCHES +#define SUBTARGET_OPTIONS +#define SUBTARGET_OVERRIDE_OPTIONS + +/* target machine storage layout */ + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +#define LONG_DOUBLE_TYPE_SIZE 96 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* #define REAL_ARITHMETIC */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. + This is true for 68020 insns such as bfins and bfexts. + We make it true always by avoiding using the single-bit insns + except in special cases with constant bit numbers. */ +#define BITS_BIG_ENDIAN 1 + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is true on the 68000. */ +#define BYTES_BIG_ENDIAN 1 + +/* Define this if most significant word of a multiword number is the lowest + numbered. */ +/* For 68000 we can decide arbitrarily + since there are no machine instructions for them. + So let's be consistent. */ +#define WORDS_BIG_ENDIAN 1 + +/* number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 68000, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY (TARGET_SHORT ? 16 : 32) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY (1 << (m68k_align_funcs + 3)) + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. + Most published ABIs say that ints should be aligned on 16 bit + boundaries, but cpus with 32 bit busses get better performance + aligned on 32 bit boundaries. Coldfires without a misalignment + module require 32 bit alignment. */ +#define BIGGEST_ALIGNMENT (TARGET_ALIGN_INT ? 32 : 16) + +/* Set this nonzero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +/* Maximum power of 2 that code can be aligned to. */ +#define MAX_CODE_ALIGN 2 /* 4 byte alignment */ + +/* Align loop starts for optimal branching. */ +#define LOOP_ALIGN(LABEL) (m68k_align_loops) + +/* This is how to align an instruction for optimal branching. */ +#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (m68k_align_jumps) + +#define SELECT_RTX_SECTION(MODE, X) \ +{ \ + if (!flag_pic) \ + readonly_data_section(); \ + else if (LEGITIMATE_PIC_OPERAND_P (X)) \ + readonly_data_section(); \ + else \ + data_section(); \ +} + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ + +#define INT_TYPE_SIZE (TARGET_SHORT ? 16 : 32) + +/* Define these to avoid dependence on meaning of `int'. + Note that WCHAR_TYPE_SIZE is used in cexp.y, + where TARGET_SHORT is not available. */ + +#define WCHAR_TYPE "long int" +#define WCHAR_TYPE_SIZE 32 + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. + For the 68000, we give the data registers numbers 0-7, + the address registers numbers 010-017, + and the 68881 floating point registers numbers 020-027. */ +#ifndef SUPPORT_SUN_FPA +#define FIRST_PSEUDO_REGISTER 24 +#else +#define FIRST_PSEUDO_REGISTER 56 +#endif + +/* This defines the register which is used to hold the offset table for PIC. */ +#define PIC_OFFSET_TABLE_REGNUM 13 + +/* Used to output a (use pic_offset_table_rtx) so that we + always save/restore a5 in functions that use PIC relocation + at *any* time during the compilation process. */ +#define FINALIZE_PIC finalize_pic() + +#ifndef SUPPORT_SUN_FPA + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 68000, only the stack pointer is such. */ + +#define FIXED_REGISTERS \ + {/* Data registers. */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + \ + /* Address registers. */ \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + \ + /* Floating point registers \ + (if available). */ \ + 0, 0, 0, 0, 0, 0, 0, 0 } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0 } + +#else /* SUPPORT_SUN_FPA */ + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 68000, only the stack pointer is such. */ + +/* fpa0 is also reserved so that it can be used to move data back and + forth between high fpa regs and everything else. */ + +#define FIXED_REGISTERS \ + {/* Data registers. */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + \ + /* Address registers. */ \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + \ + /* Floating point registers \ + (if available). */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + \ + /* Sun3 FPA registers. */ \ + 1, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0 } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ + {1, 1, 0, 0, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 0, 0, 0, 0, 0, 0, \ + /* FPA registers. */ \ + 1, 1, 1, 1, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0 } + +#endif /* defined SUPPORT_SUN_FPA */ + + +/* Make sure everything's fine if we *don't* have a given processor. + This assumes that putting a register in fixed_regs will keep the + compiler's mitts completely off it. We don't bother to zero it out + of register classes. If neither TARGET_FPA or TARGET_68881 is set, + the compiler won't touch since no instructions that use these + registers will be valid. */ + +#ifdef SUPPORT_SUN_FPA + +#define CONDITIONAL_REGISTER_USAGE \ +{ \ + int i; \ + HARD_REG_SET x; \ + if (!TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FPA_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ + if (TARGET_FPA) \ + { \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FP_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ +} + +#endif /* defined SUPPORT_SUN_FPA */ + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + On the 68000, ordinary registers hold 32 bits worth; + for the 68881 registers, a single register is always enough for + anything that can be stored in them at all. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO) >= 16 ? GET_MODE_NUNITS (MODE) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +#ifndef SUPPORT_SUN_FPA + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 68000, the cpu registers can hold any mode but the 68881 registers + can hold only SFmode or DFmode. The 68881 registers can't hold anything + if 68881 use is disabled. */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 16 \ + && !((REGNO) < 8 && (REGNO) + GET_MODE_SIZE (MODE) / 4 > 8)) \ + || ((REGNO) >= 16 && (REGNO) < 24 \ + && TARGET_68881 \ + && (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ + && GET_MODE_UNIT_SIZE (MODE) <= 12)) + +#else /* defined SUPPORT_SUN_FPA */ + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 68000, the cpu registers can hold any mode but the 68881 registers + can hold only SFmode or DFmode. And the 68881 registers can't hold anything + if 68881 use is disabled. However, the Sun FPA register can + (apparently) hold whatever you feel like putting in them. + If using the fpa, don't put a double in d7/a0. */ + +/* ??? This is confused. The check to prohibit d7/a0 overlaps should always + be enabled regardless of whether TARGET_FPA is specified. It isn't clear + what the other d/a register checks are for. Every check using REGNO + actually needs to use a range, e.g. 24>=X<56 not <56. There is probably + no one using this code anymore. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ +(((REGNO) < 16 \ + && !(TARGET_FPA \ + && GET_MODE_CLASS ((MODE)) != MODE_INT \ + && GET_MODE_UNIT_SIZE ((MODE)) > 4 \ + && (REGNO) < 8 && (REGNO) + GET_MODE_SIZE ((MODE)) / 4 > 8 \ + && (REGNO) % (GET_MODE_UNIT_SIZE ((MODE)) / 4) != 0)) \ + || ((REGNO) < 24 \ + ? (TARGET_68881 \ + && (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ + && GET_MODE_UNIT_SIZE (MODE) <= 12) \ + : ((REGNO) < 56 ? TARGET_FPA && GET_MODE_UNIT_SIZE (MODE) <= 8 : 0))) + +#endif /* defined SUPPORT_SUN_FPA */ + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (! TARGET_68881 \ + || ((GET_MODE_CLASS (MODE1) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \ + == (GET_MODE_CLASS (MODE2) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT))) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* m68000 pc isn't overloaded on a register. */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 15 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 14 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED 0 + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 14 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 8 + +/* Register in which address to store a structure value + is passed to a function. */ +#define STRUCT_VALUE_REGNUM 9 + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +/* The 68000 has three kinds of registers, so eight classes would be + a complete set. One of them is not needed. */ + +#ifndef SUPPORT_SUN_FPA + +enum reg_class { + NO_REGS, DATA_REGS, + ADDR_REGS, FP_REGS, + GENERAL_REGS, DATA_OR_FP_REGS, + ADDR_OR_FP_REGS, ALL_REGS, + LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + { "NO_REGS", "DATA_REGS", \ + "ADDR_REGS", "FP_REGS", \ + "GENERAL_REGS", "DATA_OR_FP_REGS", \ + "ADDR_OR_FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + {0x00000000}, /* NO_REGS */ \ + {0x000000ff}, /* DATA_REGS */ \ + {0x0000ff00}, /* ADDR_REGS */ \ + {0x00ff0000}, /* FP_REGS */ \ + {0x0000ffff}, /* GENERAL_REGS */ \ + {0x00ff00ff}, /* DATA_OR_FP_REGS */ \ + {0x00ffff00}, /* ADDR_OR_FP_REGS */ \ + {0x00ffffff}, /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) (((REGNO)>>3)+1) + +#else /* defined SUPPORT_SUN_FPA */ + +/* + * Notes on final choices: + * + * 1) Didn't feel any need to union-ize LOW_FPA_REGS with anything + * else. + * 2) Removed all unions that involve address registers with + * floating point registers (left in unions of address and data with + * floating point). + * 3) Defined GENERAL_REGS as ADDR_OR_DATA_REGS. + * 4) Defined ALL_REGS as FPA_OR_FP_OR_GENERAL_REGS. + * 4) Left in everything else. + */ +enum reg_class { NO_REGS, LO_FPA_REGS, FPA_REGS, FP_REGS, + FP_OR_FPA_REGS, DATA_REGS, DATA_OR_FPA_REGS, DATA_OR_FP_REGS, + DATA_OR_FP_OR_FPA_REGS, ADDR_REGS, GENERAL_REGS, + GENERAL_OR_FPA_REGS, GENERAL_OR_FP_REGS, ALL_REGS, + LIM_REG_CLASSES }; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ + { "NO_REGS", "LO_FPA_REGS", "FPA_REGS", "FP_REGS", \ + "FP_OR_FPA_REGS", "DATA_REGS", "DATA_OR_FPA_REGS", "DATA_OR_FP_REGS", \ + "DATA_OR_FP_OR_FPA_REGS", "ADDR_REGS", "GENERAL_REGS", \ + "GENERAL_OR_FPA_REGS", "GENERAL_OR_FP_REGS", "ALL_REGS" } + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + {0, 0}, /* NO_REGS */ \ + {0xff000000, 0x000000ff}, /* LO_FPA_REGS */ \ + {0xff000000, 0x00ffffff}, /* FPA_REGS */ \ + {0x00ff0000, 0x00000000}, /* FP_REGS */ \ + {0xffff0000, 0x00ffffff}, /* FP_OR_FPA_REGS */ \ + {0x000000ff, 0x00000000}, /* DATA_REGS */ \ + {0xff0000ff, 0x00ffffff}, /* DATA_OR_FPA_REGS */ \ + {0x00ff00ff, 0x00000000}, /* DATA_OR_FP_REGS */ \ + {0xffff00ff, 0x00ffffff}, /* DATA_OR_FP_OR_FPA_REGS */\ + {0x0000ff00, 0x00000000}, /* ADDR_REGS */ \ + {0x0000ffff, 0x00000000}, /* GENERAL_REGS */ \ + {0xff00ffff, 0x00ffffff}, /* GENERAL_OR_FPA_REGS */\ + {0x00ffffff, 0x00000000}, /* GENERAL_OR_FP_REGS */\ + {0xffffffff, 0x00ffffff}, /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +extern enum reg_class regno_reg_class[]; +#define REGNO_REG_CLASS(REGNO) (regno_reg_class[(REGNO)>>3]) + +#endif /* SUPPORT_SUN_FPA */ + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS GENERAL_REGS +#define BASE_REG_CLASS ADDR_REGS + +/* Get reg_class from a letter such as appears in the machine description. + We do a trick here to modify the effective constraints on the + machine description; we zorch the constraint letters that aren't + appropriate for a specific target. This allows us to guarantee + that a specific kind of register will not be used for a given target + without fiddling with the register classes above. */ + +#ifndef SUPPORT_SUN_FPA + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? (TARGET_68881 ? FP_REGS : \ + NO_REGS) : \ + NO_REGS))) + +#else /* defined SUPPORT_SUN_FPA */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'a' ? ADDR_REGS : \ + ((C) == 'd' ? DATA_REGS : \ + ((C) == 'f' ? (TARGET_68881 ? FP_REGS : \ + NO_REGS) : \ + ((C) == 'x' ? (TARGET_FPA ? FPA_REGS : \ + NO_REGS) : \ + ((C) == 'y' ? (TARGET_FPA ? LO_FPA_REGS : \ + NO_REGS) : \ + NO_REGS))))) + +#endif /* defined SUPPORT_SUN_FPA */ + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + For the 68000, `I' is used for the range 1 to 8 + allowed as immediate shift counts and in addq. + `J' is used for the range of signed numbers that fit in 16 bits. + `K' is for numbers that moveq can't handle. + `L' is for range -8 to -1, range of values that can be added with subq. + `M' is for numbers that moveq+notb can't handle. + 'N' is for range 24 to 31, rotatert:SI 8 to 1 expressed as rotate. + 'O' is for 16 (for rotate using swap). + 'P' is for range 8 to 15, rotatert:HI 8 to 1 expressed as rotate. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) > 0 && (VALUE) <= 8 : \ + (C) == 'J' ? (VALUE) >= -0x8000 && (VALUE) <= 0x7FFF : \ + (C) == 'K' ? (VALUE) < -0x80 || (VALUE) >= 0x80 : \ + (C) == 'L' ? (VALUE) < 0 && (VALUE) >= -8 : \ + (C) == 'M' ? (VALUE) < -0x100 || (VALUE) >= 0x100 : \ + (C) == 'N' ? (VALUE) >= 24 && (VALUE) <= 31 : \ + (C) == 'O' ? (VALUE) == 16 : \ + (C) == 'P' ? (VALUE) >= 8 && (VALUE) <= 15 : 0) + +/* + * A small bit of explanation: + * "G" defines all of the floating constants that are *NOT* 68881 + * constants. this is so 68881 constants get reloaded and the + * fpmovecr is used. "H" defines *only* the class of constants that + * the fpa can use, because these can be gotten at in any fpa + * instruction and there is no need to force reloads. + */ +#ifndef SUPPORT_SUN_FPA +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? ! (TARGET_68881 && standard_68881_constant_p (VALUE)) : 0 ) +#else /* defined SUPPORT_SUN_FPA */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? ! (TARGET_68881 && standard_68881_constant_p (VALUE)) : \ + (C) == 'H' ? (TARGET_FPA && standard_sun_fpa_constant_p (VALUE)) : 0) +#endif /* defined SUPPORT_SUN_FPA */ + +/* A C expression that defines the optional machine-dependent constraint + letters that can be used to segregate specific types of operands, + usually memory references, for the target machine. It should return 1 if + VALUE corresponds to the operand type represented by the constraint letter + C. If C is not defined as an extra constraint, the value returned should + be 0 regardless of VALUE. */ + +/* For the m68k, `Q' means address register indirect addressing mode. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? (GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG) : \ + 0 ) + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. + On the 68000 series, use a data reg if possible when the + value is a constant in the range where moveq could be used + and we ensure that QImodes are reloaded into data regs. + Also, if a floating constant needs reloading, put it in memory. + Don't do this for !G constants, since all patterns in the md file + expect them to be loaded into a register via fpmovecr. See above. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + ((GET_CODE (X) == CONST_INT \ + && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ + && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : (GET_MODE (X) == QImode && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : (GET_CODE (X) == CONST_DOUBLE \ + && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \ + ? (! CONST_DOUBLE_OK_FOR_LETTER_P (X, 'G') \ + && (CLASS == FP_REGS || CLASS == DATA_OR_FP_REGS) \ + ? FP_REGS : NO_REGS) \ + : (CLASS)) + +/* Force QImode output reloads from subregs to be allocated to data regs, + since QImode stores from address regs are not supported. We make the + assumption that if the class is not ADDR_REGS, then it must be a superset + of DATA_REGS. */ + +#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ + (((MODE) == QImode && (CLASS) != ADDR_REGS) \ + ? DATA_REGS \ + : (CLASS)) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 68000, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#ifndef SUPPORT_SUN_FPA + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between fp regs and other regs are two insns. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + (((CLASS1) == FP_REGS && (CLASS2) != FP_REGS) \ + || ((CLASS2) == FP_REGS && (CLASS1) != FP_REGS) \ + ? 4 : 2) + +#else /* defined SUPPORT_SUN_FPA */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((CLASS) == FP_REGS || (CLASS) == FPA_REGS || (CLASS) == LO_FPA_REGS ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Moves between fp regs and other regs are two insns. */ +/* Likewise for high fpa regs and other regs. */ +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + ((((CLASS1) == FP_REGS && (CLASS2) != FP_REGS) \ + || ((CLASS2) == FP_REGS && (CLASS1) != FP_REGS) \ + || ((CLASS1) == FPA_REGS && (CLASS2) != FPA_REGS) \ + || ((CLASS2) == FPA_REGS && (CLASS1) != FPA_REGS)) \ + ? 4 : 2) + +#endif /* define SUPPORT_SUN_FPA */ + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Nonzero if we need to generate stack-probe insns. + On most systems they are not needed. + When they are needed, define this as the stack offset to probe at. */ +#define NEED_PROBE 0 + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On the 68000, sp@- in a byte insn really pushes a word. + On the 5200 (coldfire), sp@- in a byte insn pushes just a byte. */ +#define PUSH_ROUNDING(BYTES) (TARGET_5200 ? BYTES : ((BYTES) + 1) & ~1) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 8 + +/* Offset of the CFA from the argument pointer register value. */ +#define ARG_POINTER_CFA_OFFSET 8 + +/* Value is the number of byte of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the 68000, the RTS insn cannot pop anything. + On the 68010, the RTD insn may be used to pop them if the number + of args is fixed, but if the number is variable then the caller + must pop them all. RTD can't be used for library calls now + because the library is compiled with the Unix compiler. + Use of RTD is a selectable option, since it is incompatible with + standard Unix calling sequences. If the option is not selected, + the caller must always pop the args. */ + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((TARGET_RTD && (!(FUNDECL) || TREE_CODE (FUNDECL) != IDENTIFIER_NODE) \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) \ + ? (SIZE) : 0) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ + +/* On the 68000 the return value is in D0 regardless. */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx_REG (TYPE_MODE (VALTYPE), 0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the 68000 the return value is in D0 regardless. */ + +#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, 0) + +/* 1 if N is a possible register number for a function value. + On the 68000, d0 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#define NEEDS_UNTYPED_CALL 0 + +/* Define this if PCC uses the nonreentrant convention for returning + structure and union values. */ + +#define PCC_STATIC_STRUCT_RETURN + +/* 1 if N is a possible register number for function argument passing. + On the 68000, no registers are used in this way. */ + +#define FUNCTION_ARG_REGNO_P(N) 0 + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the m68k, this is a single integer, which is a number of bytes + of arguments scanned so far. */ + +#define CUMULATIVE_ARGS int + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. + + On the m68k, the offset starts at 0. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ + ((CUM) = 0) + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM) += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +/* On the 68000 all args are pushed, except if -mregparm is specified + then the first two words of arguments are passed in d0, d1. + *NOTE* -mregparm does not work. + It exists only to test register calling conventions. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8) ? gen_rtx_REG ((MODE), (CUM) / 4) : 0) + +/* For an arg passed partly in registers and partly in memory, + this is the number of registers used. + For args passed entirely in registers or entirely in memory, zero. */ + +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM) < 8 \ + && 8 < ((CUM) + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM) / 4 : 0) + +/* Generate the assembly code for function entry. */ +#define FUNCTION_PROLOGUE(FILE, SIZE) output_function_prologue(FILE, SIZE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + asm_fprintf (FILE, "\tlea %LLP%d,%Ra0\n\tjsr mcount\n", (LABELNO)) + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \ +do \ + { \ + switch (profile_block_flag) \ + { \ + case 2: \ + asm_fprintf (FILE, "\tpea %d\n\tpea %LLPBX0\n\tjsr %U__bb_init_trace_func\n\taddql %I8,%Rsp\n", \ + (BLOCK_OR_LABEL)); \ + break; \ + \ + default: \ + asm_fprintf (FILE, "\ttstl %LLPBX0\n\tbne %LLPI%d\n\tpea %LLPBX0\n\tjsr %U__bb_init_func\n\taddql %I4,%Rsp\n%LLPI%d:\n", \ + (BLOCK_OR_LABEL), (BLOCK_OR_LABEL)); \ + break; \ + } \ + } \ +while(0) + +/* Output assembler code to FILE to increment the counter for + the BLOCKNO'th basic block in this source file. */ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ +do \ + { \ + switch (profile_block_flag) \ + { \ + case 2: \ + asm_fprintf (FILE, "\tmovel %Ra1,%Rsp@-\n\tlea ___bb,%Ra1\n\tmovel %I%d,%Ra1@(0)\n\tmovel %I%LLPBX0,%Ra1@(4)\n\tmovel %Rsp@+,%Ra1\n\tjsr %U__bb_trace_func\n", \ + BLOCKNO); \ + break; \ + \ + default: \ + asm_fprintf (FILE, "\taddql %I1,%LLPBX2+%d\n", 4 * BLOCKNO); \ + break; \ + } \ + } \ +while(0) + +/* Output assembler code to FILE to indicate return from + a function during basic block profiling. */ + +#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \ + asm_fprintf (FILE, "\tjsr %U__bb_trace_ret\n"); + +/* Save all registers which may be clobbered by a function call. + MACHINE_STATE_SAVE and MACHINE_STATE_RESTORE are target-code macros, + used in libgcc2.c. They may not refer to TARGET_* macros !!! */ +#if defined (__mc68010__) || defined(mc68010) \ + || defined(__mc68020__) || defined(mc68020) \ + || defined(__mc68030__) || defined(mc68030) \ + || defined(__mc68040__) || defined(mc68040) \ + || defined(__mcpu32__) || defined(mcpu32) +#define MACHINE_STATE_m68010_up +#endif + +#ifdef MOTOROLA +#if defined(__mcf5200__) +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("sub.l 20,%sp"); \ + asm ("movm.l &0x0303,4(%sp)"); \ + asm ("move.w %ccr,%d0"); \ + asm ("movm.l &0x0001,(%sp)"); \ + } +#else /* !__mcf5200__ */ +#if defined(MACHINE_STATE_m68010_up) +#ifdef __HPUX_ASM__ +/* HPUX assembler does not accept %ccr. */ +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("move.w %cc,-(%sp)"); \ + asm ("movm.l &0xc0c0,-(%sp)"); \ + } +#else /* ! __HPUX_ASM__ */ +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("move.w %ccr,-(%sp)"); \ + asm ("movm.l &0xc0c0,-(%sp)"); \ + } +#endif /* __HPUX_ASM__ */ +#else /* !MACHINE_STATE_m68010_up */ +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("move.w %sr,-(%sp)"); \ + asm ("movm.l &0xc0c0,-(%sp)"); \ + } +#endif /* MACHINE_STATE_m68010_up */ +#endif /* __mcf5200__ */ +#else /* !MOTOROLA */ +#if defined(__mcf5200__) +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("subl %#20,%/sp" : ); \ + asm ("movml %/d0/%/d1/%/a0/%/a1,%/sp@(4)" : ); \ + asm ("movew %/cc,%/d0" : ); \ + asm ("movml %/d0,%/sp@" : ); \ + } +#else /* !__mcf5200__ */ +#if defined(MACHINE_STATE_m68010_up) +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("movew %/cc,%/sp@-" : ); \ + asm ("moveml %/d0/%/d1/%/a0/%/a1,%/sp@-" : ); \ + } +#else /* !MACHINE_STATE_m68010_up */ +#define MACHINE_STATE_SAVE(id) \ + { \ + asm ("movew %/sr,%/sp@-" : ); \ + asm ("moveml %/d0/%/d1/%/a0/%/a1,%/sp@-" : ); \ + } +#endif /* MACHINE_STATE_m68010_up */ +#endif /* __mcf5200__ */ +#endif /* MOTOROLA */ + +/* Restore all registers saved by MACHINE_STATE_SAVE. */ + +#ifdef MOTOROLA +#if defined(__mcf5200__) +#define MACHINE_STATE_RESTORE(id) \ + { \ + asm ("movm.l (%sp),&0x0001"); \ + asm ("move.w %d0,%ccr"); \ + asm ("movm.l 4(%sp),&0x0303"); \ + asm ("add.l 20,%sp"); \ + } +#else /* !__mcf5200__ */ +#ifdef __HPUX_ASM__ +/* HPUX assembler does not accept %ccr. */ +#define MACHINE_STATE_RESTORE(id) \ + { \ + asm ("movm.l (%sp)+,&0x0303"); \ + asm ("move.w (%sp)+,%cc"); \ + } +#else /* ! __HPUX_ASM__ */ +#define MACHINE_STATE_RESTORE(id) \ + { \ + asm ("movm.l (%sp)+,&0x0303"); \ + asm ("move.w (%sp)+,%ccr"); \ + } +#endif /* __HPUX_ASM__ */ +#endif /* __mcf5200__ */ +#else /* !MOTOROLA */ +#if defined(__mcf5200__) +#define MACHINE_STATE_RESTORE(id) \ + { \ + asm ("movml %/sp@,%/d0" : ); \ + asm ("movew %/d0,%/cc" : ); \ + asm ("movml %/sp@(4),%/d0/%/d1/%/a0/%/a1" : ); \ + asm ("addl %#20,%/sp" : ); \ + } +#else /* !__mcf5200__ */ +#define MACHINE_STATE_RESTORE(id) \ + { \ + asm ("moveml %/sp@+,%/d0/%/d1/%/a0/%/a1" : ); \ + asm ("movew %/sp@+,%/cc" : ); \ + } +#endif /* __mcf5200__ */ +#endif /* MOTOROLA */ + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ + +#define EXIT_IGNORE_STACK 1 + +/* Generate the assembly code for function exit. */ +#define FUNCTION_EPILOGUE(FILE, SIZE) output_function_epilogue (FILE, SIZE) + +/* This is a hook for other tm files to change. */ +/* #define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) */ + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define USE_RETURN_INSN use_return_insn () + +/* Store in the variable DEPTH the initial difference between the + frame pointer reg contents and the stack pointer reg contents, + as of the start of the function body. This depends on the layout + of the fixed parts of the stack frame and on how registers are saved. + + On the 68k, if we have a frame, we must add one word to its length + to allow for the place that a6 is stored when we do have a frame pointer. + Otherwise, we would need to compute the offset from the frame pointer + of a local variable as a function of frame_pointer_needed, which + is hard. */ + +#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \ +{ int regno; \ + int offset = -4; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 4; \ + (DEPTH) = (offset + ((get_frame_size () + 3) & -4) \ + + (get_frame_size () == 0 ? 0 : 4)); \ +} + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. */ + +/* On the 68k, the trampoline looks like this: + movl #STATIC,a0 + jmp FUNCTION + + WARNING: Targets that may run on 68040+ cpus must arrange for + the instruction cache to be flushed. Previous incarnations of + the m68k trampoline code attempted to get around this by either + using an out-of-line transfer function or pc-relative data, but + the fact remains that the code to jump to the transfer function + or the code to load the pc-relative data needs to be flushed + just as much as the "variable" portion of the trampoline. + Recognizing that a cache flush is going to be required anyway, + dispense with such notions and build a smaller trampoline. */ + +/* Since more instructions are required to move a template into + place than to create it on the spot, don't use a template. */ + +/* Length in units of the trampoline for entering a nested function. */ + +#define TRAMPOLINE_SIZE 12 + +/* Alignment required for a trampoline in bits. */ + +#define TRAMPOLINE_ALIGNMENT 16 + +/* Targets redefine this to invoke code to either flush the cache, + or enable stack execution (or both). */ + +#ifndef FINALIZE_TRAMPOLINE +#define FINALIZE_TRAMPOLINE(TRAMP) +#endif + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. + + We generate a two-instructions program at address TRAMP : + movea.l &CXT,%a0 + jmp FNADDR */ + +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx_MEM (HImode, TRAMP), GEN_INT(0x207C)); \ + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 2)), CXT); \ + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (TRAMP, 6)), \ + GEN_INT(0x4EF9)); \ + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 8)), FNADDR); \ + FINALIZE_TRAMPOLINE(TRAMP); \ +} + +/* This is the library routine that is used + to transfer control from the trampoline + to the actual nested function. + It is defined for backward compatibility, + for linking with object code that used the old + trampoline definition. */ + +/* A colon is used with no explicit operands + to cause the template string to be scanned for %-constructs. */ +/* The function name __transfer_from_trampoline is not actually used. + The function definition just permits use of "asm with operands" + (though the operand list is empty). */ +#define TRANSFER_FROM_TRAMPOLINE \ +void \ +__transfer_from_trampoline () \ +{ \ + register char *a0 asm ("%a0"); \ + asm (GLOBAL_ASM_OP " ___trampoline"); \ + asm ("___trampoline:"); \ + asm volatile ("move%.l %0,%@" : : "m" (a0[22])); \ + asm volatile ("move%.l %1,%0" : "=a" (a0) : "m" (a0[18])); \ + asm ("rts":); \ +} + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_POST_INCREMENT 1 +/* #define HAVE_POST_DECREMENT 0 */ + +#define HAVE_PRE_DECREMENT 1 +/* #define HAVE_PRE_INCREMENT 0 */ + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ +((REGNO) < 16 || (unsigned) reg_renumber[REGNO] < 16) +#define REGNO_OK_FOR_BASE_P(REGNO) \ +(((REGNO) ^ 010) < 8 || (unsigned) (reg_renumber[REGNO] ^ 010) < 8) +#define REGNO_OK_FOR_DATA_P(REGNO) \ +((REGNO) < 8 || (unsigned) reg_renumber[REGNO] < 8) +#define REGNO_OK_FOR_FP_P(REGNO) \ +(((REGNO) ^ 020) < 8 || (unsigned) (reg_renumber[REGNO] ^ 020) < 8) +#ifdef SUPPORT_SUN_FPA +#define REGNO_OK_FOR_FPA_P(REGNO) \ +(((REGNO) >= 24 && (REGNO) < 56) || (reg_renumber[REGNO] >= 24 && reg_renumber[REGNO] < 56)) +#endif + +/* Now macros that check whether X is a register and also, + strictly, whether it is in a specified class. + + These macros are specific to the 68000, and may be used only + in code for printing assembler insns and in conditions for + define_optimization. */ + +/* 1 if X is a data register. */ + +#define DATA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_DATA_P (REGNO (X))) + +/* 1 if X is an fp register. */ + +#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X))) + +/* 1 if X is an address register */ + +#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) + +#ifdef SUPPORT_SUN_FPA +/* 1 if X is a register in the Sun FPA. */ +#define FPA_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FPA_P (REGNO (X))) +#else +/* Answer must be no if we don't have an FPA. */ +#define FPA_REG_P(X) 0 +#endif + +/* Maximum number of registers that can appear in a valid memory address. */ + +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#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) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* Nonzero if the constant value X is a legitimate general operand + when generating PIC code. It is given that flag_pic is on and + that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_PIC_OPERAND_P(X) \ + ((! symbolic_operand (X, VOIDmode) \ + && ! (GET_CODE (X) == CONST_DOUBLE && CONST_DOUBLE_MEM (X) \ + && GET_CODE (CONST_DOUBLE_MEM (X)) == MEM \ + && symbolic_operand (XEXP (CONST_DOUBLE_MEM (X), 0), \ + VOIDmode))) \ + || (GET_CODE (X) == SYMBOL_REF && SYMBOL_REF_FLAG (X))) + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) ((REGNO (X) ^ 020) >= 8) +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define REG_OK_FOR_BASE_P(X) ((REGNO (X) & ~027) != 0) + +#else + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + When generating PIC, an address involving a SYMBOL_REF is legitimate + if and only if it is the sum of pic_offset_table_rtx and the SYMBOL_REF. + We use LEGITIMATE_PIC_OPERAND_P to throw out the illegitimate addresses, + and we explicitly check for the sum of pic_offset_table_rtx and a SYMBOL_REF. + + Likewise for a LABEL_REF when generating PIC. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS. */ + +/* Allow SUBREG everywhere we allow REG. This results in better code. It + also makes function inlining work when inline functions are called with + arguments that are SUBREGs. */ + +#define LEGITIMATE_BASE_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \ + || (GET_CODE (X) == SUBREG \ + && GET_CODE (SUBREG_REG (X)) == REG \ + && REG_OK_FOR_BASE_P (SUBREG_REG (X)))) + +#define INDIRECTABLE_1_ADDRESS_P(X) \ + ((CONSTANT_ADDRESS_P (X) && (!flag_pic || LEGITIMATE_PIC_OPERAND_P (X))) \ + || LEGITIMATE_BASE_REG_P (X) \ + || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC) \ + && LEGITIMATE_BASE_REG_P (XEXP (X, 0))) \ + || (GET_CODE (X) == PLUS \ + && LEGITIMATE_BASE_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (TARGET_68020 \ + || ((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x10000)) \ + || (GET_CODE (X) == PLUS && XEXP (X, 0) == pic_offset_table_rtx \ + && flag_pic && GET_CODE (XEXP (X, 1)) == SYMBOL_REF) \ + || (GET_CODE (X) == PLUS && XEXP (X, 0) == pic_offset_table_rtx \ + && flag_pic && GET_CODE (XEXP (X, 1)) == LABEL_REF)) \ + +#define GO_IF_NONINDEXED_ADDRESS(X, ADDR) \ +{ if (INDIRECTABLE_1_ADDRESS_P (X)) goto ADDR; } + +/* Only labels on dispatch tables are valid for indexing from. */ +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ rtx temp; \ + if (GET_CODE (X) == LABEL_REF \ + && (temp = next_nonnote_insn (XEXP (X, 0))) != 0 \ + && GET_CODE (temp) == JUMP_INSN \ + && (GET_CODE (PATTERN (temp)) == ADDR_VEC \ + || GET_CODE (PATTERN (temp)) == ADDR_DIFF_VEC)) \ + goto ADDR; \ + if (LEGITIMATE_BASE_REG_P (X)) goto ADDR; } + +#define GO_IF_INDEXING(X, ADDR) \ +{ if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 0))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 1), ADDR); } \ + if (GET_CODE (X) == PLUS && LEGITIMATE_INDEX_P (XEXP (X, 1))) \ + { GO_IF_INDEXABLE_BASE (XEXP (X, 0), ADDR); } } + +#define GO_IF_INDEXED_ADDRESS(X, ADDR) \ +{ GO_IF_INDEXING (X, ADDR); \ + if (GET_CODE (X) == PLUS) \ + { if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (TARGET_68020 || (unsigned) INTVAL (XEXP (X, 1)) + 0x80 < 0x100)) \ + { rtx go_temp = XEXP (X, 0); GO_IF_INDEXING (go_temp, ADDR); } \ + if (GET_CODE (XEXP (X, 0)) == CONST_INT \ + && (TARGET_68020 || (unsigned) INTVAL (XEXP (X, 0)) + 0x80 < 0x100)) \ + { rtx go_temp = XEXP (X, 1); GO_IF_INDEXING (go_temp, ADDR); } } } + +/* coldfire/5200 does not allow HImode index registers. */ +#define LEGITIMATE_INDEX_REG_P(X) \ + ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ + || (! TARGET_5200 \ + && GET_CODE (X) == SIGN_EXTEND \ + && GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == HImode \ + && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ + || (GET_CODE (X) == SUBREG \ + && GET_CODE (SUBREG_REG (X)) == REG \ + && REG_OK_FOR_INDEX_P (SUBREG_REG (X)))) + +#define LEGITIMATE_INDEX_P(X) \ + (LEGITIMATE_INDEX_REG_P (X) \ + || ((TARGET_68020 || TARGET_5200) && GET_CODE (X) == MULT \ + && LEGITIMATE_INDEX_REG_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 2 \ + || INTVAL (XEXP (X, 1)) == 4 \ + || (INTVAL (XEXP (X, 1)) == 8 && !TARGET_5200)))) + +/* If pic, we accept INDEX+LABEL, which is what do_tablejump makes. */ +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ GO_IF_NONINDEXED_ADDRESS (X, ADDR); \ + GO_IF_INDEXED_ADDRESS (X, ADDR); \ + if (flag_pic && MODE == CASE_VECTOR_MODE && GET_CODE (X) == PLUS \ + && LEGITIMATE_INDEX_P (XEXP (X, 0)) \ + && GET_CODE (XEXP (X, 1)) == LABEL_REF) \ + goto ADDR; } + +/* Don't call memory_address_noforce for the address to fetch + the switch offset. This address is ok as it stands (see above), + but memory_address_noforce would alter it. */ +#define PIC_CASE_VECTOR_ADDRESS(index) index + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. + + For the 68000, we handle X+REG by loading X into a register R and + using R+REG. R will go in an address reg and indexing will be used. + However, if REG is a broken-out memory address or multiplication, + nothing needs to be done because REG can certainly go in an address reg. */ + +#define COPY_ONCE(Y) if (!copied) { Y = copy_rtx (Y); copied = ch = 1; } +#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \ +{ register int ch = (X) != (OLDX); \ + if (GET_CODE (X) == PLUS) \ + { int copied = 0; \ + if (GET_CODE (XEXP (X, 0)) == MULT) \ + { COPY_ONCE (X); XEXP (X, 0) = force_operand (XEXP (X, 0), 0);} \ + if (GET_CODE (XEXP (X, 1)) == MULT) \ + { COPY_ONCE (X); XEXP (X, 1) = force_operand (XEXP (X, 1), 0);} \ + if (ch && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == REG) \ + goto WIN; \ + if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); } \ + if (GET_CODE (XEXP (X, 0)) == REG \ + || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 1), 0); \ + emit_move_insn (temp, val); \ + COPY_ONCE (X); \ + XEXP (X, 1) = temp; \ + goto WIN; } \ + else if (GET_CODE (XEXP (X, 1)) == REG \ + || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND \ + && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG \ + && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode)) \ + { register rtx temp = gen_reg_rtx (Pmode); \ + register rtx val = force_operand (XEXP (X, 0), 0); \ + emit_move_insn (temp, val); \ + COPY_ONCE (X); \ + XEXP (X, 0) = temp; \ + goto WIN; }}} + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 68000, only predecrement and postincrement address depend thus + (the amount of decrement or increment being the length of the operand). */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ + if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE HImode + +/* Define as C expression which evaluates to nonzero if the tablejump + instruction expects the table to contain offsets from the address of the + table. + Do not define this if the table should contain absolute addresses. */ +#define CASE_VECTOR_PC_RELATIVE 1 + +/* Specify the tree operation to be used to convert reals to integers. */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Don't cse the address of the function being compiled. */ +#define NO_RECURSIVE_FUNCTION_CSE + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Define this if zero-extension is slow (more than one real instruction). */ +#define SLOW_ZERO_EXTEND + +/* Nonzero if access to memory by bytes is slow and undesirable. */ +#define SLOW_BYTE_ACCESS 0 + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE -1 + +/* When a prototype says `char' or `short', really pass an `int'. */ +#define PROMOTE_PROTOTYPES + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Compute the cost of computing a constant rtl expression RTX + whose rtx-code is CODE. The body of this macro is a portion + of a switch statement. If the code is computed here, + return it with a return statement. Otherwise, break from the switch. */ + +#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ + case CONST_INT: \ + /* Constant zero is super cheap due to clr instruction. */ \ + if (RTX == const0_rtx) return 0; \ + /* if ((OUTER_CODE) == SET) */ \ + return const_int_cost(RTX); \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 3; \ + case CONST_DOUBLE: \ + return 5; + +/* Compute the cost of various arithmetic operations. + These are vaguely right for a 68020. */ +/* The costs for long multiply have been adjusted to + work properly in synth_mult on the 68020, + relative to an average of the time for add and the time for shift, + taking away a little more because sometimes move insns are needed. */ +/* div?.w is relatively cheaper on 68000 counted in COSTS_N_INSNS terms. */ +#define MULL_COST (TARGET_68060 ? 2 : TARGET_68040 ? 5 : 13) +#define MULW_COST (TARGET_68060 ? 2 : TARGET_68040 ? 3 : TARGET_68020 ? 8 : 5) +#define DIVW_COST (TARGET_68020 ? 27 : 12) + +#define RTX_COSTS(X,CODE,OUTER_CODE) \ + case PLUS: \ + /* An lea costs about three times as much as a simple add. */ \ + if (GET_MODE (X) == SImode \ + && GET_CODE (XEXP (X, 1)) == REG \ + && GET_CODE (XEXP (X, 0)) == MULT \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \ + && (INTVAL (XEXP (XEXP (X, 0), 1)) == 2 \ + || INTVAL (XEXP (XEXP (X, 0), 1)) == 4 \ + || INTVAL (XEXP (XEXP (X, 0), 1)) == 8)) \ + return COSTS_N_INSNS (3); /* lea an@(dx:l:i),am */ \ + break; \ + case ASHIFT: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + if (TARGET_68060) \ + return COSTS_N_INSNS(1); \ + if (! TARGET_68020) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + if (INTVAL (XEXP (X, 1)) < 16) \ + return COSTS_N_INSNS (2) + INTVAL (XEXP (X, 1)) / 2; \ + else \ + /* We're using clrw + swap for these cases. */ \ + return COSTS_N_INSNS (4) + (INTVAL (XEXP (X, 1)) - 16) / 2; \ + } \ + return COSTS_N_INSNS (10); /* worst case */ \ + } \ + /* A shift by a big integer takes an extra instruction. */ \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && (INTVAL (XEXP (X, 1)) == 16)) \ + return COSTS_N_INSNS (2); /* clrw;swap */ \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && !(INTVAL (XEXP (X, 1)) > 0 \ + && INTVAL (XEXP (X, 1)) <= 8)) \ + return COSTS_N_INSNS (3); /* lsr #i,dn */ \ + break; \ + case MULT: \ + if ((GET_CODE (XEXP (X, 0)) == ZERO_EXTEND \ + || GET_CODE (XEXP (X, 0)) == SIGN_EXTEND) \ + && GET_MODE (X) == SImode) \ + return COSTS_N_INSNS (MULW_COST); \ + if (GET_MODE (X) == QImode || GET_MODE (X) == HImode) \ + return COSTS_N_INSNS (MULW_COST); \ + else \ + return COSTS_N_INSNS (MULL_COST); \ + case DIV: \ + case UDIV: \ + case MOD: \ + case UMOD: \ + if (GET_MODE (X) == QImode || GET_MODE (X) == HImode) \ + return COSTS_N_INSNS (DIVW_COST); /* div.w */ \ + return COSTS_N_INSNS (43); /* div.l */ + +/* Tell final.c how to eliminate redundant test instructions. */ + +/* Here we define machine-dependent flags and fields in cc_status + (see `conditions.h'). */ + +/* Set if the cc value is actually in the 68881, so a floating point + conditional branch must be output. */ +#define CC_IN_68881 04000 + +/* Store in cc_status the expressions that the condition codes will + describe after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +/* On the 68000, all the insns to store in an address register fail to + set the cc's. However, in some cases these instructions can make it + possibly invalid to use the saved cc's. In those cases we clear out + some or all of the saved cc's so they won't be used. */ + +#define NOTICE_UPDATE_CC(EXP,INSN) notice_update_cc (EXP, INSN) + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ if (cc_prev_status.flags & CC_IN_68881) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; } + +/* Control the assembler format that we output. */ + +/* Output at beginning of assembler file. */ + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "#NO_APP\n"); + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "#APP\n" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "#NO_APP\n" + +/* Output before read-only data. */ + +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Here are four prefixes that are used by asm_fprintf to + facilitate customization for alternate assembler syntaxes. + Machines with no likelihood of an alternate syntax need not + define these and need not use asm_fprintf. */ + +/* The prefix for register names. Note that REGISTER_NAMES + is supposed to include this prefix. */ + +#define REGISTER_PREFIX "" + +/* The prefix for local labels. You should be able to define this as + an empty string, or any arbitrary string (such as ".", ".L%", etc) + without having to make any other changes to account for the specific + definition. Note it is a string literal, not interpreted by printf + and friends. */ + +#define LOCAL_LABEL_PREFIX "" + +/* The prefix to add to user-visible assembler symbols. */ + +#define USER_LABEL_PREFIX "_" + +/* The prefix for immediate operands. */ + +#define IMMEDIATE_PREFIX "#" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#ifndef SUPPORT_SUN_FPA + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7" } + +#else /* SUPPORTED_SUN_FPA */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpa0", "fpa1", "fpa2", "fpa3", "fpa4", "fpa5", "fpa6", "fpa7", \ + "fpa8", "fpa9", "fpa10", "fpa11", "fpa12", "fpa13", "fpa14", "fpa15", \ + "fpa16", "fpa17", "fpa18", "fpa19", "fpa20", "fpa21", "fpa22", "fpa23", \ + "fpa24", "fpa25", "fpa26", "fpa27", "fpa28", "fpa29", "fpa30", "fpa31" } + +#endif /* defined SUPPORT_SUN_FPA */ + +/* How to renumber registers for dbx and gdb. + On the Sun-3, the floating point registers have numbers + 18 to 25, not 16 to 23 as they do in the compiler. */ + +#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 16 ? (REGNO) : (REGNO) + 2) + +/* Before the prologue, RA is at 0(%sp). */ +#define INCOMING_RETURN_ADDR_RTX \ + gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM)) + +/* We must not use the DBX register numbers for the DWARF 2 CFA column + numbers because that maps to numbers beyond FIRST_PSEUDO_REGISTER. + Instead use the identity mapping. */ +#define DWARF_FRAME_REGNUM(REG) REG + +/* Before the prologue, the top of the frame is at 4(%sp). */ +#define INCOMING_FRAME_SP_OFFSET 4 + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define GLOBAL_ASM_OP ".globl" +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fprintf (FILE, "%s ", GLOBAL_ASM_OP); \ + assemble_name (FILE, NAME); \ + fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + asm_fprintf (FILE, "%0U%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + asm_fprintf (FILE, "%0L%s%d:\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%s%d", LOCAL_LABEL_PREFIX, PREFIX, NUM) + +/* This is how to output a `long double' extended real constant. */ + +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf (FILE, "\t.long 0x%lx,0x%lx,0x%lx\n", l[0], l[1], l[2]); \ + } while (0) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf (FILE, "\t.long 0x%lx\n", l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t.word "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t.byte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t.byte 0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + asm_fprintf (FILE, "\tmovel %s,%Rsp@-\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + asm_fprintf (FILE, "\tmovel %Rsp@+,%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + asm_fprintf (FILE, "\t.long %LL%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\t.word %LL%d-%LL%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. */ + +/* We don't have a way to align to more than a two-byte boundary, so do the + best we can and don't complain. */ +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) >= 1) \ + fprintf (FILE, "\t.even\n"); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.skip %u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ + +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE == 'f') \ + { \ + char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9g", dstr); \ + asm_fprintf ((FILE), "%I0r%s", dstr); \ + } \ + else \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + } while (0) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (FILE, "%I0r%s", dstr); \ + } while (0) + +/* Note, long double immediate operands are not actually + generated by m68k.md. */ +#define ASM_OUTPUT_LONG_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (FILE, "%I0r%s", dstr); \ + } while (0) + +/* Print operand X (an rtx) in assembler syntax to file FILE. + CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. + For `%' followed by punctuation, CODE is the punctuation and X is null. + + On the 68000, we use several CODE characters: + '.' for dot needed in Motorola-style opcode names. + '-' for an operand pushing on the stack: + sp@-, -(sp) or -(%sp) depending on the style of syntax. + '+' for an operand pushing on the stack: + sp@+, (sp)+ or (%sp)+ depending on the style of syntax. + '@' for a reference to the top word on the stack: + sp@, (sp) or (%sp) depending on the style of syntax. + '#' for an immediate operand prefix (# in MIT and Motorola syntax + but & in SGS syntax). + '!' for the fpcr register (used in some float-to-fixed conversions). + '$' for the letter `s' in an op code, but only on the 68040. + '&' for the letter `d' in an op code, but only on the 68040. + '/' for register prefix needed by longlong.h. + + 'b' for byte insn (no effect, on the Sun; this is for the ISI). + 'd' to force memory addressing to be absolute, not relative. + 'f' for float insn (print a CONST_DOUBLE as a float rather than in hex) + 'w' for FPA insn (print a CONST_DOUBLE as a SunFPA constant rather + than directly). Second part of 'y' below. + 'x' for float insn (print a CONST_DOUBLE as a float rather than in hex), + or print pair of registers as rx:ry. + 'y' for a FPA insn (print pair of registers as rx:ry). This also outputs + CONST_DOUBLE's as SunFPA constant RAM registers if + possible, so it should not be used except for the SunFPA. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '.' || (CODE) == '#' || (CODE) == '-' \ + || (CODE) == '+' || (CODE) == '@' || (CODE) == '!' \ + || (CODE) == '$' || (CODE) == '&' || (CODE) == '/') + +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand X. X is an RTL + expression. + + CODE is a value that can be used to specify one of several ways + of printing the operand. It is used when identical operands + must be printed differently depending on the context. CODE + comes from the `%' specification that was used to request + printing of the operand. If the specification was just `%DIGIT' + then CODE is 0; if the specification was `%LTR DIGIT' then CODE + is the ASCII code for LTR. + + If X is a register, this macro should print the register's name. + The names can be found in an array `reg_names' whose type is + `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'. + + When the machine description has a specification `%PUNCT' (a `%' + followed by a punctuation character), this macro is called with + a null pointer for X and the punctuation character for CODE. + + See m68k.c for the m68k specific codes. */ + +#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE) + +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand that is a memory + reference whose address is ADDR. ADDR is an RTL expression. + + On some machines, the syntax for a symbolic address depends on + the section that the address refers to. On these machines, + define the macro `ENCODE_SECTION_INFO' to store the information + into the `symbol_ref', and then check for it here. */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) + +/* Define functions defined in aux-output.c and used in templates. */ + +extern char *output_move_const_into_data_reg (); +extern char *output_move_simode_const (); +extern char *output_move_simode (); +extern char *output_move_himode (); +extern char *output_move_qimode (); +extern char *output_move_stricthi (); +extern char *output_move_strictqi (); +extern char *output_move_double (); +extern char *output_move_const_single (); +extern char *output_move_const_double (); +extern char *output_btst (); +extern char *output_scc_di (); +extern char *output_addsi3 (); +extern char *output_andsi3 (); +extern char *output_iorsi3 (); +extern char *output_xorsi3 (); +extern void output_dbcc_and_branch (); +extern int const_uint32_operand (); +extern int const_sint32_operand (); +extern int floating_exact_log2 (); +extern int not_sp_operand (); +extern int valid_dbcc_comparison_p (); +extern int extend_operator (); +extern int flags_in_68881 (); +extern int strict_low_part_peephole_ok (); + +/* Variables in m68k.c */ +extern char *m68k_align_loops_string; +extern char *m68k_align_jumps_string; +extern char *m68k_align_funcs_string; +extern int m68k_align_loops; +extern int m68k_align_jumps; +extern int m68k_align_funcs; +extern int m68k_last_compare_had_fp_operands; + +/* Functions from m68k.c used in macros. */ +extern int symbolic_operand (); +extern int const_int_cost (); +extern int standard_68881_constant_p (); +extern int standard_sun_fpa_constant_p (); +extern void output_function_prologue (); +extern void output_function_epilogue (); +extern int use_return_insn (); +extern void print_operand_address (); +extern void print_operand (); +extern void notice_update_cc (); +extern void finalize_pic (); +extern void override_options (); + + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md new file mode 100755 index 0000000..87e76ef --- /dev/null +++ b/gcc/config/m68k/m68k.md @@ -0,0 +1,7913 @@ +;;- Machine description for GNU compiler, Motorola 68000 Version +;; Copyright (C) 1987, 88, 93-97, 1998 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. + +;;- Information about MCF5200 port. + +;;- The MCF5200 "ColdFire" architecture is a reduced version of the +;;- 68k ISA. Differences include reduced support for byte and word +;;- operands and the removal of BCD, bitfield, rotate, and integer +;;- divide instructions. The TARGET_5200 flag turns the use of the +;;- removed opcodes and addressing modes off. +;;- + + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + +;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code +;;- updates for most instructions. + +;;- Operand classes for the register allocator: +;;- 'a' one of the address registers can be used. +;;- 'd' one of the data registers can be used. +;;- 'f' one of the m68881 registers can be used +;;- 'r' either a data or an address register can be used. +;;- 'x' if one of the Sun FPA registers +;;- 'y' if one of the Low Sun FPA registers (fpa0-fpa15). + +;;- Immediate Floating point operator constraints +;;- 'G' a floating point constant that is *NOT* one of the standard +;; 68881 constant values (to force calling output_move_const_double +;; to get it from rom if it is a 68881 constant). +;;- 'H' one of the standard FPA constant values +;; +;; See the functions standard_XXX_constant_p in output-m68k.c for more +;; info. + +;;- Immediate integer operand constraints: +;;- 'I' 1 .. 8 +;;- 'J' -32768 .. 32767 +;;- 'K' all integers EXCEPT -128 .. 127 +;;- 'L' -8 .. -1 +;;- 'M' all integers EXCEPT -256 .. 255 +;;- 'N' 24 .. 31 +;;- 'O' 16 +;;- 'P' 8 .. 15 + +;;- Assembler specs: +;;- "%." size separator ("." or "") move%.l d0,d1 +;;- "%#" immediate separator ("#" or "") move%.l %#0,d0 +;;- "%-" push operand "sp@-" move%.l d0,%- +;;- "%+" pop operand "sp@+" move%.l d0,%+ +;;- "%@" top of stack "sp@" move%.l d0,%@ +;;- "%!" fpcr register +;;- "%$" single-precision fp specifier ("s" or "") f%$add.x fp0,fp1 +;;- "%&" double-precision fp specifier ("d" or "") f%&add.x fp0,fp1 + +;; UNSPEC usage: +;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT. +;; operand 1 is the argument for `sin'. +;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT. +;; operand 1 is the argument for `cos'. + +;;- Information about 68040 port. + +;;- The 68040 executes all 68030 and 68881/2 instructions, but some must +;;- be emulated in software by the OS. It is faster to avoid these +;;- instructions and issue a library call rather than trapping into +;;- the kernel. The affected instructions are fintrz and fscale. The +;;- TARGET_68040 flag turns the use of the opcodes off. + +;;- The '040 also implements a set of new floating-point instructions +;;- which specify the rounding precision in the opcode. This finally +;;- permit the 68k series to be truly IEEE compliant, and solves all +;;- issues of excess precision accumulating in the extended registers. +;;- By default, GCC does not use these instructions, since such code will +;;- not run on an '030. To use these instructions, use the -m68040-only +;;- switch. By changing TARGET_DEFAULT to include TARGET_68040_ONLY, +;;- you can make these instructions the default. + +;;- These new instructions aren't directly in the md. They are brought +;;- into play by defining "%$" and "%&" to expand to "s" and "d" rather +;;- than "". + +;;- Information about 68060 port. + +;;- The 68060 executes all 68030 and 68881/2 instructions, but some must +;;- be emulated in software by the OS. It is faster to avoid these +;;- instructions and issue a library call rather than trapping into +;;- the kernel. The affected instructions are: divs.l <ea>,Dr:Dq; +;;- divu.l <ea>,Dr:Dq; muls.l <ea>,Dr:Dq; mulu.l <ea>,Dr:Dq; and +;;- fscale. The TARGET_68060 flag turns the use of the opcodes off. + +;;- FPA port explanation: + +;;- Usage of the Sun FPA and the 68881 together + +;;- The current port of gcc to the sun fpa disallows use of the m68881 +;;- instructions completely if code is targeted for the fpa. This is +;;- for the following reasons: + +;;- 1) Expressing the preference hierarchy (ie. use the fpa if you +;;- can, the 68881 otherwise, and data registers only if you are +;;- forced to it) is a bitch with the current constraint scheme, +;;- especially since it would have to work for any combination of +;;- -mfpa, -m68881. + +;;- 2) There are no instructions to move between the two types of +;;- registers; the stack must be used as an intermediary. + +;;- It could indeed be done; I think the best way would be to have +;;- separate patterns for TARGET_FPA (which implies a 68881), +;;- TARGET_68881, and no floating point co-processor. Use +;;- define_expands for all of the named instruction patterns, and +;;- include code in the FPA instruction to deal with the 68881 with +;;- preferences specifically set to favor the fpa. Some of this has +;;- already been done: +;;- +;;- 1) Separation of most of the patterns out into a TARGET_FPA +;;- case and a TARGET_68881 case (the exceptions are the patterns +;;- which would need one define_expand and three define_insn's under +;;- it (with a lot of duplicate code between them) to replace the +;;- current single define_insn. These are mov{[ds]f,[ds]i} and the +;;- first two patterns in the md. +;;- +;;- Some would still have to be done: +;;- +;;- 1) Add code to the fpa patterns which correspond to 68881 +;;- patterns to deal with the 68881 case (including preferences!). +;;- What you might actually do here is combine the fpa and 68881 code +;;- back together into one pattern for those instructions where it's +;;- absolutely necessary and save yourself some duplicate code. I'm +;;- not completely sure as to whether you could get away with doing +;;- this only for the mov* insns, or if you'd have to do it for all +;;- named insns. +;;- 2) Add code to the mov{[ds]f,[ds]i} instructions to handle +;;- moving between fpa regs and 68881 regs. + +;;- Since the fpa is more powerful than the 68881 and also has more +;;- registers, and since I think the resultant md would be medium ugly +;;- (lot's of duplicate code, ugly constraint strings), I elected not +;;- to do this change. + +;;- Another reason why someone *might* want to do the change is to +;;- control which register classes are accessed in a slightly cleaner +;;- way than I have. See the blurb on CONDITIONAL_REGISTER_USAGE in +;;- the internals manual. + +;;- Yet another reason why someone might want to do this change is to +;;- allow use of some of the 68881 insns which have no equivalent on +;;- the fpa. The sqrt instruction comes fairly quickly to mind. + +;;- If this is ever done, don't forget to change sun3.h so that +;;- it *will* define __HAVE_68881__ when the FPA is in use. + +;;- Condition code hack + +;;- When a floating point compare is done in the fpa, the resulting +;;- condition codes are left in the fpastatus register. The values in +;;- this register must be moved into the 68000 cc register before any +;;- jump is executed. Once this has been done, regular jump +;;- instructions are fine (ie. floating point jumps are not necessary. +;;- They are only done if the cc is in the 68881). + +;;- The instructions that move the fpastatus register to the 68000 +;;- register clobber a data register (the move cannot be done direct). +;;- These instructions might be bundled either with the compare +;;- instruction, or the branch instruction. If we were using both the +;;- fpa and the 68881 together, we would wish to only mark the +;;- register clobbered if we were doing the compare in the fpa, but I +;;- think that that decision (whether to clobber the register or not) +;;- must be done before register allocation (makes sense) and hence we +;;- can't know if the floating point compare will be done in the fpa +;;- or the fp. So whenever we are asked for code that uses the fpa, +;;- we will mark a data register as clobbered. This is reasonable, as +;;- almost all floating point compare operations done with fpa code +;;- enabled will be done in the fpa. It's even more reasonable since +;;- we decided to make the 68881 and the fpa mutually exclusive. + +;;- We place to code to move the fpastatus register inside of a +;;- define_expand so that we can do it conditionally based on whether +;;- we are targeting an fpa or not. + +;;- This still leaves us with the question of where we wish to put the +;;- code to move the fpastatus reg. If we put it in the compare +;;- instruction, we can restrict the clobbering of the register to +;;- floating point compares, but we can't take advantage of floating +;;- point subtracts & etc. that alter the fpastatus register. If we +;;- put it in the branch instruction, all branches compiled with fpa +;;- code enabled will clobber a data register, but we will be able to +;;- take advantage of fpa subtracts. This balance favors putting the +;;- code in with the compare instruction. + +;;- Note that if some enterprising hacker should decide to switch +;;- this, he'll need to modify the code in NOTICE_UPDATE_CC. + +;;- Usage of the top 16 fpa registers + +;;- The only locations which we may transfer fpa registers 16-31 from +;;- or to are the fpa registers 0-15. (68000 registers and memory +;;- locations are impossible). This causes problems in gcc, which +;;- assumes that mov?? instructions require no additional registers +;;- (see section 11.7) and since floating point moves *must* be +;;- supported into general registers (see section 12.3 under +;;- HARD_REGNO_OK_FOR_MODE_P) from anywhere. + +;;- My solution was to reserve fpa0 for moves into or out of these top +;;- 16 registers and to disparage the choice to reload into or out of +;;- these registers as much as I could. That alternative is always +;;- last in the list, so it will not be used unless all else fails. I +;;- will note that according to my current information, sun's compiler +;;- doesn't use these top 16 registers at all. + +;;- There is another possible way to do it. I *believe* that if you +;;- make absolutely sure that the code will not be executed in the +;;- reload pass, you can support the mov?? names with define_expands +;;- which require new registers. This may be possible by the +;;- appropriate juggling of constraints. I may come back to this later. + +;;- Usage of constant RAM + +;;- This has been handled correctly (I believe) but the way I've done +;;- it could use a little explanation. The constant RAM can only be +;;- accessed when the instruction is in "command register" mode. +;;- "command register" mode means that no accessing of memory or the +;;- 68000 registers is being done. This can be expressed easily in +;;- constraints, so generally the mode of the instruction is +;;- determined by a branch off of which_alternative. In outputting +;;- instructions, a 'w' means to output an access to the constant ram +;;- (if the arg is CONST_DOUBLE and is one of the available +;;- constants), and 'x' means to output a register pair (if the arg is +;;- a 68000 register) and a 'y' is the combination of the above two +;;- processes. You use a 'y' in two operand DF instructions where you +;;- *know* the other operand is an fpa register, you use an 'x' in DF +;;- instructions where the arg might be a 68000 register and the +;;- instruction is *not* in "command register" mode, and you use a 'w' +;;- in two situations: 1) The instruction *is* in command register +;;- mode (and hence won't be accessing 68000 registers), or 2) The +;;- instruction is a two operand SF instruction where you know the +;;- other operand is an fpa register. + +;;- Optimization issues + +;;- I actually think that I've included all of the fpa instructions +;;- that should be included. Note that if someone is interested in +;;- doing serious floating point work on the sun fpa, I would advise +;;- the use of the "asm" instruction in gcc to allow you to use the +;;- sin, cos, and exponential functions on the fpa board. + +;;- END FPA Explanation Section. + + +;;- Some of these insn's are composites of several m68000 op codes. +;;- The assembler (or final @@??) insures that the appropriate one is +;;- selected. + +(define_insn "" + [(set (match_operand:DF 0 "push_operand" "=m") + (match_operand:DF 1 "general_operand" "ro<>fyE"))] + "" + "* +{ + if (FP_REG_P (operands[1])) + return \"fmove%.d %f1,%0\"; + if (FPA_REG_P (operands[1])) + return \"fpmove%.d %1, %x0\"; + return output_move_double (operands); +}") + +(define_insn "pushdi" + [(set (match_operand:DI 0 "push_operand" "=m") + (match_operand:DI 1 "general_operand" "ro<>Fyi"))] + "" + "* +{ + return output_move_double (operands); +}") + +;; 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_expand "tstdi" + [(parallel [(set (cc0) + (match_operand:DI 0 "nonimmediate_operand" "")) + (clobber (match_scratch:SI 1 "")) + (clobber (match_scratch:DI 2 ""))])] + "" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (match_operand:DI 0 "nonimmediate_operand" "am,d")) + (clobber (match_scratch:SI 1 "=X,d")) + (clobber (match_scratch:DI 2 "=d,X"))] + "" + "* +{ + if (which_alternative == 0) + { + rtx xoperands[2]; + + xoperands[0] = operands[2]; + xoperands[1] = operands[0]; + output_move_double (xoperands); + cc_status.flags |= CC_REVERSED; + return \"neg%.l %R2\;negx%.l %2\"; + } + if (find_reg_note (insn, REG_DEAD, operands[0])) + { + cc_status.flags |= CC_REVERSED; + return \"neg%.l %R0\;negx%.l %0\"; + } + else + /* + ** 'sub' clears %1, and also clears the X cc bit + ** 'tst' sets the Z cc bit according to the low part of the DImode operand + ** 'subx %1' (i.e. subx #0) acts as a (non-existent) tstx on the high part + */ + return \"sub%.l %1,%1\;tst%.l %R0\;subx%.l %1,%0\"; +}") + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" ""))] + "" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ +#ifdef ISI_OV + /* ISI's assembler fails to handle tstl a0. */ + if (! ADDRESS_REG_P (operands[0])) +#else + if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (operands[0])) +#endif + return \"tst%.l %0\"; + /* If you think that the 68020 does not support tstl a0, + reread page B-167 of the 68020 manual more carefully. */ + /* On an address reg, cmpw may replace cmpl. */ +#ifdef SGS_CMP_ORDER + return \"cmp%.w %0,%#0\"; +#else + return \"cmp%.w %#0,%0\"; +#endif +}") + +;; This can't use an address register, because comparisons +;; with address registers as second operand always test the whole word. +(define_expand "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" ""))] + "" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "dm"))] + "" + "tst%.w %0") + +(define_expand "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" ""))] + "" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "dm"))] + "" + "tst%.b %0") + +(define_expand "tstsf" + [(set (cc0) + (match_operand:SF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + m68k_last_compare_had_fp_operands = 1; + if (TARGET_FPA) + { + emit_insn (gen_tstsf_fpa (operands[0])); + DONE; + } +}") + +(define_insn "tstsf_fpa" + [(set (cc0) + (match_operand:SF 0 "general_operand" "xmdF")) + (clobber (match_scratch:SI 1 "=d"))] + "TARGET_FPA" + "fptst%.s %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:SF 0 "general_operand" "fdm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.s %0\"; +}") + +(define_expand "tstdf" + [(set (cc0) + (match_operand:DF 0 "general_operand" ""))] + "TARGET_68881 || TARGET_FPA" + " +{ + m68k_last_compare_had_fp_operands = 1; + if (TARGET_FPA) + { + emit_insn (gen_tstsf_fpa (operands[0])); + DONE; + } +}") + +(define_insn "tstdf_fpa" + [(set (cc0) + (match_operand:DF 0 "general_operand" "xrmF")) + (clobber (match_scratch:SI 1 "=d"))] + "TARGET_FPA" + "fptst%.d %x0\;fpmove fpastatus,%1\;movw %1,cc") + +(define_insn "" + [(set (cc0) + (match_operand:DF 0 "general_operand" "fm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + if (FP_REG_P (operands[0])) + return \"ftst%.x %0\"; + return \"ftst%.d %0\"; +}") + +;; compare instructions. + +(define_expand "cmpdi" + [(parallel + [(set (cc0) + (compare (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))) + (clobber (match_dup 2))])] + "" + "m68k_last_compare_had_fp_operands = 0; operands[2] = gen_reg_rtx (DImode);") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DI 1 "nonimmediate_operand" "0,d") + (match_operand:DI 2 "general_operand" "d,0"))) + (clobber (match_operand:DI 0 "register_operand" "=d,d"))] + "" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"sub%.l %R2,%R0\;subx%.l %2,%0\"; + else + { + cc_status.flags |= CC_REVERSED; + return \"sub%.l %R1,%R0\;subx%.l %1,%0\"; + } +}") + +;; This is the second "hook" for PIC code (in addition to movsi). See +;; comment of movsi for a description of PIC handling. +(define_expand "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + m68k_last_compare_had_fp_operands = 0; + if (flag_pic && symbolic_operand (operands[1], SImode)) + { + /* The source is an address which requires PIC relocation. + Call legitimize_pic_address with the source, mode, and a relocation + register (a new pseudo, or the final destination if reload_in_progress + is set). Then fall through normally */ + extern rtx legitimize_pic_address(); + rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); + operands[1] = legitimize_pic_address (operands[1], SImode, temp); + } +}") + +;; A composite of the cmp, cmpa, cmpi & cmpm m68000 op codes. +(define_insn "" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "rKs,mr,>") + (match_operand:SI 1 "general_operand" "mr,rKs,>")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +#ifdef SGS_CMP_ORDER + return \"cmpm%.l %0,%1\"; +#else + return \"cmpm%.l %1,%0\"; +#endif + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef SGS_CMP_ORDER + return \"cmp%.l %d1,%d0\"; +#else + return \"cmp%.l %d0,%d1\"; +#endif + } +#ifdef SGS_CMP_ORDER + return \"cmp%.l %d0,%d1\"; +#else + return \"cmp%.l %d1,%d0\"; +#endif +}") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "mrKs,r") + (match_operand:SI 1 "general_operand" "r,mrKs")))] + "TARGET_5200" + "* +{ + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef SGS_CMP_ORDER + return \"cmp%.l %d1,%d0\"; +#else + return \"cmp%.l %d0,%d1\"; +#endif + } +#ifdef SGS_CMP_ORDER + return \"cmp%.l %d0,%d1\"; +#else + return \"cmp%.l %d1,%d0\"; +#endif +}") + +(define_expand "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "!TARGET_5200" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "rnm,d,n,m,>") + (match_operand:HI 1 "general_operand" "d,rnm,m,n,>")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +#ifdef SGS_CMP_ORDER + return \"cmpm%.w %0,%1\"; +#else + return \"cmpm%.w %1,%0\"; +#endif + if ((REG_P (operands[1]) && !ADDRESS_REG_P (operands[1])) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef SGS_CMP_ORDER + return \"cmp%.w %d1,%d0\"; +#else + return \"cmp%.w %d0,%d1\"; +#endif + } +#ifdef SGS_CMP_ORDER + return \"cmp%.w %d0,%d1\"; +#else + return \"cmp%.w %d1,%d0\"; +#endif +}") + +(define_expand "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "!TARGET_5200" + "m68k_last_compare_had_fp_operands = 0;") + +(define_insn "" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "dn,md,>") + (match_operand:QI 1 "general_operand" "dm,nd,>")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) +#ifdef SGS_CMP_ORDER + return \"cmpm%.b %0,%1\"; +#else + return \"cmpm%.b %1,%0\"; +#endif + if (REG_P (operands[1]) + || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) + { cc_status.flags |= CC_REVERSED; +#ifdef SGS_CMP_ORDER + return \"cmp%.b %d1,%d0\"; +#else + return \"cmp%.b %d0,%d1\"; +#endif + } +#ifdef SGS_CMP_ORDER + return \"cmp%.b %d0,%d1\"; +#else + return \"cmp%.b %d1,%d0\"; +#endif +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + m68k_last_compare_had_fp_operands = 1; + if (TARGET_FPA) + { + emit_insn (gen_cmpdf_fpa (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "cmpdf_fpa" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "x,y") + (match_operand:DF 1 "general_operand" "xH,rmF"))) + (clobber (match_scratch:SI 2 "=d,d"))] + "TARGET_FPA" + "fpcmp%.d %y1,%0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:DF 0 "general_operand" "f,mG") + (match_operand:DF 1 "general_operand" "fmG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef SGS_CMP_ORDER + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.d %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %1,%f0\"; +#else + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.d %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.d %f0,%1\"; +#endif +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + " +{ + m68k_last_compare_had_fp_operands = 1; + if (TARGET_FPA) + { + emit_insn (gen_cmpsf_fpa (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "cmpsf_fpa" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "x,y") + (match_operand:SF 1 "general_operand" "xH,rmF"))) + (clobber (match_scratch:SI 2 "=d,d"))] + "TARGET_FPA" + "fpcmp%.s %w1,%x0\;fpmove fpastatus,%2\;movw %2,cc") + +(define_insn "" + [(set (cc0) + (compare (match_operand:SF 0 "general_operand" "f,mdG") + (match_operand:SF 1 "general_operand" "fmdG,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef SGS_CMP_ORDER + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.s %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %1,%f0\"; +#else + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.s %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.s %f0,%1\"; +#endif +}") + +;; Recognizers for btst instructions. + +;; Coldfire/5200 only allows "<Q>" type addresses when the bit position is +;; specified as a constant, so we must disable all patterns that may extract +;; from a MEM at a constant bit position if we can't use this as a constraint. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "o") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "di"))))] + "!TARGET_5200" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +;; This is the same as the above pattern except for the constraints. The 'i' +;; has been deleted. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "o") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "d"))))] + "TARGET_5200" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (match_operand:SI 1 "general_operand" "di"))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; The following two patterns are like the previous two +;; except that they use the fact that bit-number operands +;; are automatically masked to 3 or 5 bits. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "o") + (const_int 1) + (minus:SI (const_int 7) + (and:SI + (match_operand:SI 1 "register_operand" "d") + (const_int 7)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 7); }") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "d") + (const_int 1) + (minus:SI (const_int 31) + (and:SI + (match_operand:SI 1 "register_operand" "d") + (const_int 31)))))] + "" + "* { return output_btst (operands, operands[1], operands[0], insn, 31); }") + +;; Nonoffsettable mem refs are ok in this one pattern +;; since we don't try to adjust them. +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "n")))] + "(unsigned) INTVAL (operands[1]) < 8 && !TARGET_5200" + "* +{ + operands[1] = GEN_INT (7 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 7); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "do") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "n")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = GEN_INT (7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = GEN_INT (31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + +;; This is the same as the above pattern except for the constraints. +;; The 'o' has been replaced with 'Q'. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "dQ") + (const_int 1) + (match_operand:SI 1 "const_int_operand" "n")))] + "TARGET_5200" + "* +{ + if (GET_CODE (operands[0]) == MEM) + { + operands[0] = adj_offsettable_operand (operands[0], + INTVAL (operands[1]) / 8); + operands[1] = GEN_INT (7 - INTVAL (operands[1]) % 8); + return output_btst (operands, operands[1], operands[0], insn, 7); + } + operands[1] = GEN_INT (31 - INTVAL (operands[1])); + return output_btst (operands, operands[1], operands[0], insn, 31); +}") + + +;; move instructions + +;; A special case in which it is not desirable +;; to reload the constant into a data register. +(define_insn "pushexthisi_const" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "const_int_operand" "J"))] + "INTVAL (operands[1]) >= -0x8000 && INTVAL (operands[1]) < 0x8000" + "* +{ + if (operands[1] == const0_rtx) + return \"clr%.l %0\"; + return \"pea %a1\"; +}") + +;This is never used. +;(define_insn "swapsi" +; [(set (match_operand:SI 0 "general_operand" "+r") +; (match_operand:SI 1 "general_operand" "+r")) +; (set (match_dup 1) (match_dup 0))] +; "" +; "exg %1,%0") + +;; Special case of fullword move when source is zero. +;; The reason this is special is to avoid loading a zero +;; into a data reg with moveq in order to store it elsewhere. + +(define_insn "movsi_const0" + [(set (match_operand:SI 0 "general_operand" "=g") + (const_int 0))] + ;; clr insns on 68000 read before writing. + ;; This isn't so on the 68010, but we have no TARGET_68010. + "((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))" + "* +{ + if (ADDRESS_REG_P (operands[0])) + { + /* On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 */ + if (!TARGET_68040 && !TARGET_68060) + return \"sub%.l %0,%0\"; + else + { +#ifdef MOTOROLA +#ifdef SGS + /* Many SGS assemblers croak on size specifiers for constants. */ + return \"lea 0,%0\"; +#else + return \"lea 0.w,%0\"; +#endif +#else + return \"lea 0:w,%0\"; +#endif + } + } + /* moveq is faster on the 68000. */ + if (DATA_REG_P (operands[0]) && (!TARGET_68020 && !TARGET_5200)) +#if defined(MOTOROLA) && !defined(CRDS) + return \"moveq%.l %#0,%0\"; +#else + return \"moveq %#0,%0\"; +#endif + return \"clr%.l %0\"; +}") + +;; General case of fullword move. +;; +;; This is the main "hook" for PIC code. When generating +;; PIC, movsi is responsible for determining when the source address +;; needs PIC relocation and appropriately calling legitimize_pic_address +;; to perform the actual relocation. +;; +;; In both the PIC and non-PIC cases the patterns generated will +;; matched by the next define_insn. +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " +{ + if (flag_pic && symbolic_operand (operands[1], SImode)) + { + /* The source is an address which requires PIC relocation. + Call legitimize_pic_address with the source, mode, and a relocation + register (a new pseudo, or the final destination if reload_in_progress + is set). Then fall through normally */ + extern rtx legitimize_pic_address(); + rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); + operands[1] = legitimize_pic_address (operands[1], SImode, temp); + } +}") + +;; General case of fullword move. The register constraints +;; force integer constants in range for a moveq to be reloaded +;; if they are headed for memory. +(define_insn "" + ;; Notes: make sure no alternative allows g vs g. + ;; We don't allow f-regs since fixed point cannot go in them. + ;; We do allow y and x regs since fixed point is allowed in them. + [(set (match_operand:SI 0 "general_operand" "=g,da,y,!*x*r*m") + (match_operand:SI 1 "general_operand" "daymKs,i,g,*x*r*m"))] + "!TARGET_5200" + "* +{ + if (which_alternative == 3) + return \"fpmove%.l %x1,fpa0\;fpmove%.l fpa0,%x0\"; + if (FPA_REG_P (operands[1]) || FPA_REG_P (operands[0])) + return \"fpmove%.l %x1,%x0\"; + return output_move_simode (operands); +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r<Q>,g") + (match_operand:SI 1 "general_operand" "g,r<Q>"))] + "TARGET_5200" + "* return output_move_simode (operands);") + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g") + (match_operand:HI 1 "general_operand" "g"))] + "!TARGET_5200" + "* return output_move_himode (operands);") + + (define_insn "" + [(set (match_operand:HI 0 "general_operand" "=r<Q>,g") + (match_operand:HI 1 "general_operand" "g,r<Q>"))] + "TARGET_5200" + "* return output_move_himode (operands);") + +(define_expand "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "")) + (match_operand:HI 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (match_operand:HI 1 "general_operand" "rmn"))] + "!TARGET_5200" + "* return output_move_stricthi (operands);") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+d,m")) + (match_operand:HI 1 "general_operand" "rmn,r"))] + "TARGET_5200" + "* return output_move_stricthi (operands);") + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d,*a,m") + (match_operand:QI 1 "general_operand" "dmi*a,di*a,dmi"))] + "!TARGET_5200" + "* return output_move_qimode (operands);") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d<Q>,dm,d*a") + (match_operand:QI 1 "general_operand" "dmi,d<Q>,di*a"))] + "TARGET_5200" + "* return output_move_qimode (operands);") + +(define_expand "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "")) + (match_operand:QI 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (match_operand:QI 1 "general_operand" "dmn"))] + "!TARGET_5200" + "* return output_move_strictqi (operands);") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+d,m")) + (match_operand:QI 1 "general_operand" "dmn,d"))] + "TARGET_5200" + "* return output_move_strictqi (operands);") + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=rmf,x,y,rm,!x,!rm") + (match_operand:SF 1 "general_operand" "rmfF,xH,rmF,y,rm,x"))] +; [(set (match_operand:SF 0 "general_operand" "=rmf") +; (match_operand:SF 1 "general_operand" "rmfF"))] + "!TARGET_5200" + "* +{ + if (which_alternative >= 4) + return \"fpmove%.s %1,fpa0\;fpmove%.s fpa0,%0\"; + if (FPA_REG_P (operands[0])) + { + if (FPA_REG_P (operands[1])) + return \"fpmove%.s %x1,%x0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + else if (FP_REG_P (operands[1])) + return \"fmove%.s %1,sp@-\;fpmove%.d sp@+, %0\"; + return \"fpmove%.s %x1,%x0\"; + } + if (FPA_REG_P (operands[1])) + { + if (FP_REG_P (operands[0])) + return \"fpmove%.s %x1,sp@-\;fmove%.s sp@+,%0\"; + else + return \"fpmove%.s %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"f%$move%.x %1,%0\"; + else if (ADDRESS_REG_P (operands[1])) + return \"move%.l %1,%-\;f%$move%.s %+,%0\"; + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + return \"f%$move%.s %f1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (ADDRESS_REG_P (operands[0])) + return \"fmove%.s %1,%-\;move%.l %+,%0\"; + return \"fmove%.s %f1,%0\"; + } + if (operands[1] == CONST0_RTX (SFmode) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) + { + if (ADDRESS_REG_P (operands[0])) + { + /* On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 */ + if (!TARGET_68040 && !TARGET_68060) + return \"sub%.l %0,%0\"; + else + { +#ifdef MOTOROLA +#ifdef SGS + /* Many SGS assemblers croak on size specifiers for constants. */ + return \"lea 0,%0\"; +#else + return \"lea 0.w,%0\"; +#endif +#else + return \"lea 0:w,%0\"; +#endif + } + } + /* moveq is faster on the 68000. */ + if (DATA_REG_P (operands[0]) && !(TARGET_68020 || TARGET_5200)) + { +#if defined(MOTOROLA) && !defined(CRDS) + return \"moveq%.l %#0,%0\"; +#else + return \"moveq %#0,%0\"; +#endif + } + return \"clr%.l %0\"; + } + return \"move%.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=r,g") + (match_operand:SF 1 "general_operand" "g,r"))] + "TARGET_5200" + "* return \"move%.l %1,%0\";") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=rm,rf,rf,&rof<>,y,rm,x,!x,!rm") + (match_operand:DF 1 "general_operand" "rf,m,0,rofE<>,rmE,y,xH,rm,x"))] +; [(set (match_operand:DF 0 "general_operand" "=rm,&rf,&rof<>") +; (match_operand:DF 1 "general_operand" "rf,m,rofF<>"))] + "!TARGET_5200" + "* +{ + if (which_alternative == 7) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + if (FP_REG_P (operands[1])) + return \"fmove%.d %1,sp@-\;fpmove%.d sp@+,%x0\"; + return \"fpmove%.d %x1,%x0\"; + } + else if (FPA_REG_P (operands[1])) + { + if (FP_REG_P(operands[0])) + return \"fpmove%.d %x1,sp@-\;fmoved sp@+,%0\"; + else + return \"fpmove%.d %x1,%x0\"; + } + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"f%&move%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"f%&move%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"f%&move%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=r,g") + (match_operand:DF 1 "general_operand" "g,r"))] + "TARGET_5200" + "* return output_move_double (operands);") + +(define_expand "movxf" + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "" + " +{ + if (CONSTANT_P (operands[1])) + { + operands[1] = force_const_mem (XFmode, operands[1]); + if (! memory_address_p (XFmode, XEXP (operands[1], 0)) + && ! reload_in_progress) + operands[1] = change_address (operands[1], XFmode, + XEXP (operands[1], 0)); + } +}") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,!r,!f,!r") + (match_operand:XF 1 "nonimmediate_operand" "m,f,f,f,r,!r"))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); + output_asm_insn (\"move%.l %1,%-\", xoperands); + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.x %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fmove%.x %1,%0\"; + return \"fmove%.x %f1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.x %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + output_asm_insn (\"move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + /* Must be memory destination. */ + return \"fmove%.x %f1,%0\"; + } + return output_move_double (operands); +} +") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=rm,rf,&rof<>") + (match_operand:XF 1 "nonimmediate_operand" "rf,m,rof<>"))] + "! TARGET_68881 && ! TARGET_5200" + "* +{ + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); + output_asm_insn (\"move%.l %1,%-\", xoperands); + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.x %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return \"fmove%.x %1,%0\"; + return \"fmove%.x %f1,%0\"; + } + if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.x %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + output_asm_insn (\"move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.x %f1,%0\"; + } + return output_move_double (operands); +} +") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=r,g") + (match_operand:XF 1 "nonimmediate_operand" "g,r"))] + "! TARGET_68881 && TARGET_5200" + "* return output_move_double (operands);") + +(define_expand "movdi" + ;; Let's see if it really still needs to handle fp regs, and, if so, why. + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + "") + +;; movdi can apply to fp regs in some cases +(define_insn "" + ;; Let's see if it really still needs to handle fp regs, and, if so, why. + [(set (match_operand:DI 0 "general_operand" "=rm,r,&ro<>,y,rm,!*x,!rm") + (match_operand:DI 1 "general_operand" "rF,m,roi<>F,rmiF,y,rmF,*x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&r,&ro<>,!&rm,!&f,y,rm,x,!x,!rm") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfmF,rmi,y,rm,x"))] +; [(set (match_operand:DI 0 "general_operand" "=rm,&rf,&ro<>,!&rm,!&f") +; (match_operand:DI 1 "general_operand" "r,m,roi<>,fF,rfF"))] + "!TARGET_5200" + "* +{ + if (which_alternative == 8) + return \"fpmove%.d %x1,fpa0\;fpmove%.d fpa0,%x0\"; + if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) + return \"fpmove%.d %x1,%x0\"; + if (FP_REG_P (operands[0])) + { + if (FP_REG_P (operands[1])) + return \"fmove%.x %1,%0\"; + if (REG_P (operands[1])) + { + rtx xoperands[2]; + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%-\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; + } + if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_double (operands); + return \"fmove%.d %f1,%0\"; + } + else if (FP_REG_P (operands[1])) + { + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + else + return \"fmove%.d %f1,%0\"; + } + return output_move_double (operands); +}") + +(define_insn "" + [(set (match_operand:DI 0 "general_operand" "=r,g") + (match_operand:DI 1 "general_operand" "g,r"))] + "TARGET_5200" + "* return output_move_double (operands);") + +;; Thus goes after the move instructions +;; because the move instructions are better (require no spilling) +;; when they can apply. It goes before the add/sub insns +;; so we will prefer it to them. + +(define_insn "pushasi" + [(set (match_operand:SI 0 "push_operand" "=m") + (match_operand:SI 1 "address_operand" "p"))] + "" + "pea %a1") + +;; truncation instructions +(define_insn "truncsiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:SI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the move.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 3); + return \"move%.b %1,%0\"; +}") + +(define_insn "trunchiqi2" + [(set (match_operand:QI 0 "general_operand" "=dm,d") + (truncate:QI + (match_operand:HI 1 "general_operand" "doJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG + && (GET_CODE (operands[1]) == MEM + || GET_CODE (operands[1]) == CONST_INT)) + { + /* Must clear condition codes, since the move.w bases them on + the entire 16 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.w %1,%0\"; + } + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the move.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 1); + return \"move%.b %1,%0\"; +}") + +(define_insn "truncsihi2" + [(set (match_operand:HI 0 "general_operand" "=dm,d") + (truncate:HI + (match_operand:SI 1 "general_operand" "roJ,i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == REG) + { + /* Must clear condition codes, since the move.l bases them on + the entire 32 bits, not just the desired 8 bits. */ + CC_STATUS_INIT; + return \"move%.l %1,%0\"; + } + if (GET_CODE (operands[1]) == MEM) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"move%.w %1,%0\"; +}") + +;; zero extension instructions + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "general_operand" "=&d") + (zero_extend:DI (match_operand:QI 1 "general_operand" "dm")))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"moveq %#0,%0\;moveq %#0,%2\;move%.b %1,%2\"; +}") + +(define_insn "zero_extendhidi2" + [(set (match_operand:DI 0 "general_operand" "=&d") + (zero_extend:DI (match_operand:HI 1 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + return \"moveq %#0,%0\;moveq %#0,%2\;move%.w %1,%2\"; +}") + +;; this is the canonical form for (lshiftrt:DI x 32) +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "general_operand" "rm") + (zero_extend:DI (match_operand:SI 1 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"move%.l %1,%0\;clr%.l %0\"; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.l %0\;move%.l %1,%0\"; + else + operands[2] = adj_offsettable_operand (operands[0], 4); + if (GET_CODE (operands[1]) != REG || GET_CODE (operands[2]) != REG + || REGNO (operands[1]) != REGNO (operands[2])) + output_asm_insn (\"move%.l %1,%2\", operands); + if (ADDRESS_REG_P (operands[0])) + return \"sub%.l %0,%0\"; + else + return \"clr%.l %0\"; +}") + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + operands[1] = make_safe_from (operands[1], operands[0]); + if (GET_CODE (operands[0]) == SUBREG) + operands[2] = gen_rtx_SUBREG (HImode, SUBREG_REG (operands[0]), + SUBREG_WORD (operands[0])); + else + operands[2] = gen_rtx_SUBREG (HImode, operands[0], 0); +}") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + operands[1] = make_safe_from (operands[1], operands[0]); + if (GET_CODE (operands[0]) == SUBREG) + operands[2] = gen_rtx_SUBREG (QImode, SUBREG_REG (operands[0]), + SUBREG_WORD (operands[0])); + else + operands[2] = gen_rtx_SUBREG (QImode, operands[0], 0); +}") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + operands[1] = make_safe_from (operands[1], operands[0]); + if (GET_CODE (operands[0]) == SUBREG) + operands[2] = gen_rtx_SUBREG (QImode, SUBREG_REG (operands[0]), + SUBREG_WORD (operands[0])); + else + operands[2] = gen_rtx_SUBREG (QImode, operands[0], 0); +}") + +;; Patterns to recognize zero-extend insns produced by the combiner. +;; We don't allow both operands in memory, because of aliasing problems. +;; Explicitly disallow two memory operands via the condition since reloading +;; of this case will result in worse code than the uncombined patterns. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>,d<") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFFFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.w %1,%0\;and%.l %#0xFFFF,%0\"; + return \"clr%.l %0\;move%.w %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"move%.w %1,%0\;clr%.w %0\"; + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.w %0\;move%.w %1,%0\"; + else + { + output_asm_insn (\"clr%.w %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 2); + return \"move%.w %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=do<>,d") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return (!TARGET_5200 ? \"and%.w %#0xFF,%0\" : \"and%.l %#0xFF,%0\"); + if (reg_mentioned_p (operands[0], operands[1])) + return (!TARGET_5200 ? \"move%.b %1,%0\;and%.w %#0xFF,%0\" + : \"move%.b %1,%0\;and%.l %#0xFF,%0\"); + return \"clr%.w %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + if (REGNO (XEXP (XEXP (operands[0], 0), 0)) + == STACK_POINTER_REGNUM) + { + output_asm_insn (\"clr%.w %-\", operands); + operands[0] = gen_rtx_MEM (GET_MODE (operands[0]), + plus_constant (stack_pointer_rtx, 1)); + return \"move%.b %1,%0\"; + } + else + return \"move%.b %1,%0\;clr%.b %0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"clr%.b %0\;move%.b %1,%0\"; + else + { + output_asm_insn (\"clr%.b %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 1); + return \"move%.b %1,%0\"; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=do<>,d") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,m")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1])) + return \"and%.l %#0xFF,%0\"; + if (reg_mentioned_p (operands[0], operands[1])) + return \"move%.b %1,%0\;and%.l %#0xFF,%0\"; + return \"clr%.l %0\;move%.b %1,%0\"; + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr%.l -(%0)\;move%.b %1,3(%0)\"; +#else + return \"clr%.l -(%0)\;move%.b %1,(3,%0)\"; +#endif +#else + return \"clrl %0@-\;moveb %1,%0@(3)\"; +#endif + } + else if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[0] = XEXP (XEXP (operands[0], 0), 0); +#ifdef MOTOROLA +#ifdef SGS + return \"clr%.l (%0)+\;move%.b %1,-1(%0)\"; +#else + return \"clr%.l (%0)+\;move%.b %1,(-1,%0)\"; +#endif +#else + return \"clrl %0@+\;moveb %1,%0@(-1)\"; +#endif + } + else + { + output_asm_insn (\"clr%.l %0\", operands); + operands[0] = adj_offsettable_operand (operands[0], 3); + return \"move%.b %1,%0\"; + } +}") + +;; sign extension instructions + +(define_insn "extendqidi2" + [(set (match_operand:DI 0 "general_operand" "=d") + (sign_extend:DI + (match_operand:QI 1 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (TARGET_68020 || TARGET_5200) + return \"move%.b %1,%2\;extb%.l %2\;smi %0\;extb%.l %0\"; + else + return \"move%.b %1,%2\;ext%.w %0\;ext%.l %2\;move%.l %2,%0\;smi %0\"; +}") + +(define_insn "extendhidi2" + [(set (match_operand:DI 0 "general_operand" "=d") + (sign_extend:DI + (match_operand:HI 1 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (TARGET_68020 || TARGET_5200) + return \"move%.w %1,%2\;ext%.l %2\;smi %0\;extb%.l %0\"; + else + return \"move%.w %1,%2\;ext%.l %2\;smi %0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "general_operand" "=d") + (sign_extend:DI + (match_operand:SI 1 "general_operand" "rm")))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (TARGET_68020 || TARGET_5200) + return \"move%.l %1,%2\;smi %0\;extb%.l %0\"; + else + return \"move%.l %1,%2\;smi %0\;ext%.w %0\;ext%.l %0\"; +}") + +;; Special case when one can avoid register clobbering, copy and test +;; Maybe there is a way to make that the general case, by forcing the +;; result of the SI tree to be in the lower register of the DI target + +(define_insn "extendplussidi" + [(set (match_operand:DI 0 "register_operand" "=d") + (sign_extend:DI (plus:SI (match_operand:SI 1 "general_operand" "%rmn") + (match_operand:SI 2 "general_operand" "rmn"))))] + "" + "* +{ + CC_STATUS_INIT; + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (GET_CODE (operands[1]) == CONST_INT + && (unsigned) INTVAL (operands[1]) > 8) + { + rtx tmp = operands[1]; + + operands[1] = operands[2]; + operands[2] = tmp; + } + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[3])) + output_asm_insn (\"add%.l %2,%3\", operands); + else + output_asm_insn (\"move%.l %2,%3\;add%.l %1,%3\", operands); + if (TARGET_68020 || TARGET_5200) + return \"smi %0\;extb%.l %0\"; + else + return \"smi %0\;ext%.w %0\;ext%.l %0\"; +}") + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "general_operand" "=*d,a") + (sign_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "0,rm")))] + "" + "* +{ + if (ADDRESS_REG_P (operands[0])) + return \"move%.w %1,%0\"; + return \"ext%.l %0\"; +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "general_operand" "=d") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))] + "" + "ext%.w %0") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0")))] + "TARGET_68020 || TARGET_5200" + "extb%.l %0") + +;; Conversions between float and double. + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "general_operand" "") + (float_extend:DF + (match_operand:SF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (float_extend:DF + (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpstod %w1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=*fdm,f") + (float_extend:DF + (match_operand:SF 1 "general_operand" "f,dmF")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + /* Extending float to double in an fp-reg is a no-op. + NOTICE_UPDATE_CC has already assumed that the + cc will be set. So cancel what it did. */ + cc_status = cc_prev_status; + return \"\"; + } + return \"f%&move%.x %1,%0\"; + } + if (FP_REG_P (operands[0])) + return \"f%&move%.s %f1,%0\"; + if (DATA_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + return \"fmove%.d %f1,%0\"; +}") + +;; This cannot output into an f-reg because there is no way to be +;; sure of truncating in that case. +;; But on the Sun FPA, we can be sure. +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "general_operand" "") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpdtos %y1,%0") + +;; On the '040 we can truncate in a register accurately and easily. +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "fmG")))] + "TARGET_68040_ONLY" + "* +{ + if (FP_REG_P (operands[1])) + return \"f%$move%.x %1,%0\"; + return \"f%$move%.d %f1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=dm") + (float_truncate:SF + (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.s %f1,%0") + +;; Conversion between fixed point and floating point. +;; Note that among the fix-to-float insns +;; the ones that start with SImode come first. +;; That is so that an operand that is a CONST_INT +;; (and therefore lacks a specific machine mode). +;; will be recognized as SImode (which is always valid) +;; rather than as QImode or HImode. + +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "general_operand" "") + (float:SF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=y,x") + (float:SF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltos %1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "f%$move%.l %1,%0") + +(define_expand "floatsidf2" + [(set (match_operand:DF 0 "general_operand" "") + (float:DF (match_operand:SI 1 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=y,x") + (float:DF (match_operand:SI 1 "general_operand" "rmi,x")))] + "TARGET_FPA" + "fpltod %1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "f%&move%.l %1,%0") + +(define_insn "floathisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "f%$move%.w %1,%0") + +(define_insn "floathidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floatqisf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (float:SF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "floatqidf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (float:DF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "f%&move%.b %1,%0") + +;; New routines to convert floating-point values to integers +;; to be used on the '040. These should be faster than trapping +;; into the kernel to emulate fintrz. They should also be faster +;; than calling the subroutines fixsfsi or fixdfsi. + +(define_insn "fix_truncdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f")))) + (clobber (match_scratch:SI 2 "=d")) + (clobber (match_scratch:SI 3 "=d"))] + "TARGET_68881 && TARGET_68040" + "* +{ + CC_STATUS_INIT; + return \"fmovem%.l %!,%2\;moveq %#16,%3\;or%.l %2,%3\;and%.w %#-33,%3\;fmovem%.l %3,%!\;fmove%.l %1,%0\;fmovem%.l %2,%!\"; +}") + +(define_insn "fix_truncdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f")))) + (clobber (match_scratch:SI 2 "=d")) + (clobber (match_scratch:SI 3 "=d"))] + "TARGET_68881 && TARGET_68040" + "* +{ + CC_STATUS_INIT; + return \"fmovem%.l %!,%2\;moveq %#16,%3\;or%.l %2,%3\;and%.w %#-33,%3\;fmovem%.l %3,%!\;fmove%.w %1,%0\;fmovem%.l %2,%!\"; +}") + +(define_insn "fix_truncdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f")))) + (clobber (match_scratch:SI 2 "=d")) + (clobber (match_scratch:SI 3 "=d"))] + "TARGET_68881 && TARGET_68040" + "* +{ + CC_STATUS_INIT; + return \"fmovem%.l %!,%2\;moveq %#16,%3\;or%.l %2,%3\;and%.w %#-33,%3\;fmovem%.l %3,%!\;fmove%.b %1,%0\;fmovem%.l %2,%!\"; +}") + +;; Convert a float to a float whose value is an integer. +;; This is the first stage of converting it to an integer type. + +(define_insn "ftruncdf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (fix:DF (match_operand:DF 1 "general_operand" "fFm")))] + "TARGET_68881 && !TARGET_68040" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.d %f1,%0\"; +}") + +(define_insn "ftruncsf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (fix:SF (match_operand:SF 1 "general_operand" "dfFm")))] + "TARGET_68881 && !TARGET_68040" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.s %f1,%0\"; +}") + +;; Convert a float whose value is an integer +;; to an actual integer. Second stage of converting float to integer type. +(define_insn "fixsfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixsfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:SF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "fixdfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixdfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:DF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +;; Convert a float to an integer. +;; On the Sun FPA, this is done in one step. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpstol %w1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=x,y") + (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "xH,rmF"))))] + "TARGET_FPA" + "fpdtol %y1,%0") + +;; add instructions + +(define_insn "adddi_lshrdi_63" + [(set (match_operand:DI 0 "general_operand" "=d") + (plus:DI (lshiftrt:DI (match_operand:DI 1 "general_operand" "rm") + (const_int 63)) + (match_dup 1))) + (clobber (match_scratch:SI 2 "=d"))] + "" + "* +{ + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (REG_P (operands[1]) && REGNO (operands[1]) == REGNO (operands[0])) + return + \"move%.l %1,%2\;add%.l %2,%2\;subx%.l %2,%2\;sub%.l %2,%3\;subx%.l %2,%0\"; + if (GET_CODE (operands[1]) == REG) + operands[4] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC + || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + operands[4] = operands[1]; + else + operands[4] = adj_offsettable_operand (operands[1], 4); + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + output_asm_insn (\"move%.l %4,%3\", operands); + output_asm_insn (\"move%.l %1,%0\;smi %2\", operands); + if (TARGET_68020 || TARGET_5200) + output_asm_insn (\"extb%.l %2\", operands); + else + output_asm_insn (\"ext%.w %2\;ext%.l %2\", operands); + if (GET_CODE (operands[1]) != MEM + || GET_CODE (XEXP (operands[1], 0)) != PRE_DEC) + output_asm_insn (\"move%.l %4,%3\", operands); + return \"sub%.l %2,%3\;subx%.l %2,%0\"; +}") + +(define_insn "adddi_sexthishl32" + [(set (match_operand:DI 0 "general_operand" "=o,a,*d,*d") + (plus:DI (ashift:DI (sign_extend:DI + (match_operand:HI 1 "general_operand" "rm,rm,rm,rm")) + (const_int 32)) + (match_operand:DI 2 "general_operand" "0,0,0,0"))) + (clobber (match_scratch:SI 3 "=&d,X,a,?d"))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; + if (ADDRESS_REG_P (operands[0])) + return \"add%.w %1,%0\"; + else if (ADDRESS_REG_P (operands[3])) + return \"move%.w %1,%3\;add%.l %3,%0\"; + else + return \"move%.w %1,%3\;ext%.l %3\;add%.l %3,%0\"; +} ") + +(define_insn "adddi_dilshr32" + [(set (match_operand:DI 0 "general_operand" "=d,o") +;; (plus:DI (match_operand:DI 2 "general_operand" "%0") +;; (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro") +;; (const_int 32))))] + (plus:DI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro,r") + (const_int 32)) + (match_operand:DI 2 "general_operand" "0,0")))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[2] = adj_offsettable_operand (operands[0], 4); + return \"add%.l %1,%2\;negx%.l %0\;neg%.l %0\"; +} ") + +(define_insn "adddi_dishl32" + [(set (match_operand:DI 0 "general_operand" "=r,o") +;; (plus:DI (match_operand:DI 2 "general_operand" "%0") +;; (ashift:DI (match_operand:DI 1 "general_operand" "ro") +;; (const_int 32))))] + (plus:DI (ashift:DI (match_operand:DI 1 "general_operand" "ro,r") + (const_int 32)) + (match_operand:DI 2 "general_operand" "0,0")))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[1]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else + operands[1] = adj_offsettable_operand (operands[1], 4); + return \"add%.l %1,%0\"; +} ") + +(define_insn "adddi3" + [(set (match_operand:DI 0 "general_operand" "=<,o<>,d,d,d") + (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0,0") + (match_operand:DI 2 "general_operand" "<,d,no>,d,a"))) + (clobber (match_scratch:SI 3 "=X,&d,&d,X,&d"))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (DATA_REG_P (operands[2])) + return \"add%.l %R2,%R0\;addx%.l %2,%0\"; + else if (GET_CODE (operands[2]) == MEM + && GET_CODE (XEXP (operands[2], 0)) == POST_INC) + { + return \"move%.l %2,%3\;add%.l %2,%R0\;addx%.l %3,%0\"; + } + else + { + rtx xoperands[2]; + if (GET_CODE (operands[2]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1); + else if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2])); + } + else if (GET_CODE (operands[2]) == CONST_INT) + { + operands[1] = operands[2]; + operands[2] = INTVAL (operands[2]) < 0 ? constm1_rtx : const0_rtx; + } + else + operands[1] = adj_offsettable_operand (operands[2], 4); + xoperands[0] = operands[3]; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 0) + xoperands[1] = GEN_INT (-INTVAL (operands[2]) - 1); + else + xoperands[1] = operands[2]; + output_asm_insn (output_move_simode (xoperands), xoperands); + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8) + { +#ifdef NO_ADDSUB_Q + return \"add%.l %1,%R0\;addx%.l %3,%0\"; +#else + return \"addq%.l %1,%R0\;addx%.l %3,%0\"; +#endif + } + else if (INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 0) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); +#ifdef NO_ADDSUB_Q + return \"sub%.l %1,%R0\;subx%.l %3,%0\"; +#else + return \"subq%.l %1,%R0\;subx%.l %3,%0\"; +#endif + } + } + return \"add%.l %1,%R0\;addx%.l %3,%0\"; + } + } + else if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[2]) == MEM + && GET_CODE (XEXP (operands[2], 0)) == PRE_DEC) + return \"add%.l %2,%0\;addx%.l %2,%0\"; + CC_STATUS_INIT; + if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[1] + = gen_rtx_MEM (SImode, + gen_rtx_PLUS (VOIDmode, XEXP(operands[0], 0), + GEN_INT (-8))); + return \"move%.l %0,%3\;add%.l %R2,%0\;addx%.l %2,%3\;move%.l %3,%1\"; + } + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[1] = XEXP(operands[0], 0); + return \"add%.l %R2,%0\;move%.l %0,%3\;addx%.l %2,%3\;move%.l %3,%1\"; + } + else + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"add%.l %R2,%1\;move%.l %0,%3\;addx%.l %2,%3\;move%.l %3,%0\"; + } + } + else + abort (); +} ") + +(define_insn "addsi_lshrsi_31" + [(set (match_operand:SI 0 "general_operand" "=dm") + (plus:SI (lshiftrt:SI (match_operand:SI 1 "general_operand" "rm") + (const_int 31)) + (match_dup 1)))] + "" + "* +{ + operands[2] = operands[0]; + operands[3] = gen_label_rtx(); + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + operands[0] = gen_rtx_MEM (SImode, XEXP (XEXP (operands[0], 0), 0)); + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + operands[2] = gen_rtx_MEM (SImode, XEXP (XEXP (operands[0], 0), 0)); + } + output_asm_insn (\"move%.l %1,%0\", operands); +#ifdef MOTOROLA + output_asm_insn (\"jbpl %l3\", operands); +#else + output_asm_insn (\"jpl %l3\", operands); +#endif +#ifndef NO_ADDSUB_Q + output_asm_insn (\"addq%.l %#1,%2\", operands); +#else + output_asm_insn (\"add%.l %#1,%2\", operands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[3])); + return \"\"; +}") + +(define_expand "addsi3" + [(set (match_operand:SI 0 "general_operand" "") + (plus:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + +;; Note that the middle two alternatives are near-duplicates +;; in order to handle insns generated by reload. +;; This is needed since they are not themselves reloaded, +;; so commutativity won't apply to them. +(define_insn "*addsi3_internal" + [(set (match_operand:SI 0 "general_operand" "=m,?a,?a,r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJK,0") + (match_operand:SI 2 "general_operand" "dIKLs,rJK,a,mrIKLs")))] + "! TARGET_5200" + "* return output_addsi3 (operands);") + +(define_insn "*addsi3_5200" + [(set (match_operand:SI 0 "general_operand" "=m,?a,?a,r") + (plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJK,0") + (match_operand:SI 2 "general_operand" "d,rJK,a,mrIKLs")))] + "TARGET_5200" + "* return output_addsi3 (operands);") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (plus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI + (match_operand:HI 2 "nonimmediate_operand" "rm"))))] + "!TARGET_5200" + "add%.w %2,%0") + +(define_insn "addhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[2]) >= 32768) + operands[2] = GEN_INT (INTVAL (operands[2]) - 65536); + + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.w %2,%0\"; + if (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) >= -8) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return \"subq%.w %2,%0\"; + } + /* On the CPU32 it is faster to use two addqw instructions to + add a small integer (8 < N <= 16) to a register. + Likewise for subqw. */ + if (TARGET_CPU32 && REG_P (operands[0])) + { + if (INTVAL (operands[2]) > 8 + && INTVAL (operands[2]) <= 16) + { + operands[2] = GEN_INT (INTVAL (operands[2]) - 8); + return \"addq%.w %#8,%0\;addq%.w %2,%0\"; + } + if (INTVAL (operands[2]) < -8 + && INTVAL (operands[2]) >= -16) + { + operands[2] = GEN_INT (-INTVAL (operands[2]) - 8); + return \"subq%.w %#8,%0\;subq%.w %2,%0\"; + } + } +#endif + if (ADDRESS_REG_P (operands[0]) && !TARGET_68040) +#ifdef MOTOROLA + return \"lea (%c2,%0),%0\"; +#else + return \"lea %0@(%c2),%0\"; +#endif + } + return \"add%.w %2,%0\"; +}") + +;; These insns must use MATCH_DUP instead of the more expected +;; use of a matching constraint because the "output" here is also +;; an input, so you can't use the matching constraint. That also means +;; that you can't use the "%", so you need patterns with the matched +;; operand in both positions. + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[1]) >= 32768) + operands[1] = GEN_INT (INTVAL (operands[1]) - 65536); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.w %1,%0\"; + if (INTVAL (operands[1]) < 0 + && INTVAL (operands[1]) >= -8) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"subq%.w %1,%0\"; + } + /* On the CPU32 it is faster to use two addqw instructions to + add a small integer (8 < N <= 16) to a register. + Likewise for subqw. */ + if (TARGET_CPU32 && REG_P (operands[0])) + { + if (INTVAL (operands[1]) > 8 + && INTVAL (operands[1]) <= 16) + { + operands[1] = GEN_INT (INTVAL (operands[1]) - 8); + return \"addq%.w %#8,%0\;addq%.w %1,%0\"; + } + if (INTVAL (operands[1]) < -8 + && INTVAL (operands[1]) >= -16) + { + operands[1] = GEN_INT (-INTVAL (operands[1]) - 8); + return \"subq%.w %#8,%0\;subq%.w %1,%0\"; + } + } +#endif + if (ADDRESS_REG_P (operands[0]) && !TARGET_68040) +#ifdef MOTOROLA + return \"lea (%c1,%0),%0\"; +#else + return \"lea %0@(%c1),%0\"; +#endif + } + return \"add%.w %1,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (plus:HI (match_operand:HI 1 "general_operand" "dn,rmn") + (match_dup 0)))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { +#ifndef NO_ADDSUB_Q + /* If the constant would be a negative number when interpreted as + HImode, make it negative. This is usually, but not always, done + elsewhere in the compiler. First check for constants out of range, + which could confuse us. */ + + if (INTVAL (operands[1]) >= 32768) + operands[1] = GEN_INT (INTVAL (operands[1]) - 65536); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.w %1,%0\"; + if (INTVAL (operands[1]) < 0 + && INTVAL (operands[1]) >= -8) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"subq%.w %1,%0\"; + } + /* On the CPU32 it is faster to use two addqw instructions to + add a small integer (8 < N <= 16) to a register. + Likewise for subqw. */ + if (TARGET_CPU32 && REG_P (operands[0])) + { + if (INTVAL (operands[1]) > 8 + && INTVAL (operands[1]) <= 16) + { + operands[1] = GEN_INT (INTVAL (operands[1]) - 8); + return \"addq%.w %#8,%0\;addq%.w %1,%0\"; + } + if (INTVAL (operands[1]) < -8 + && INTVAL (operands[1]) >= -16) + { + operands[1] = GEN_INT (-INTVAL (operands[1]) - 8); + return \"subq%.w %#8,%0\;subq%.w %1,%0\"; + } + } +#endif + if (ADDRESS_REG_P (operands[0]) && !TARGET_68040) +#ifdef MOTOROLA + return \"lea (%c1,%0),%0\"; +#else + return \"lea %0@(%c1),%0\"; +#endif + } + return \"add%.w %1,%0\"; +}") + +(define_insn "addqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (plus:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) >= 128) + operands[2] = GEN_INT (INTVAL (operands[2]) - 256); + + if (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) <= 8) + return \"addq%.b %2,%0\"; + if (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) >= -8) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return \"subq%.b %2,%0\"; + } + } +#endif + return \"add%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) >= 128) + operands[1] = GEN_INT (INTVAL (operands[1]) - 256); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.b %1,%0\"; + if (INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -8) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"subq%.b %1,%0\"; + } + } +#endif + return \"add%.b %1,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (plus:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "!TARGET_5200" + "* +{ +#ifndef NO_ADDSUB_Q + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) >= 128) + operands[1] = GEN_INT (INTVAL (operands[1]) - 256); + + if (INTVAL (operands[1]) > 0 + && INTVAL (operands[1]) <= 8) + return \"addq%.b %1,%0\"; + if (INTVAL (operands[1]) < 0 && INTVAL (operands[1]) >= -8) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); + return \"subq%.b %1,%0\"; + } + } +#endif + return \"add%.b %1,%0\"; +}") + +(define_expand "adddf3" + [(set (match_operand:DF 0 "general_operand" "") + (plus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (plus:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,dmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.d %w2,%w1,%0\"; + return \"fpadd3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (float:DF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&add%.l %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (float:DF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&add%.w %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (float:DF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&add%.b %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (plus:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"f%&add%.x %2,%0\"; + return \"f%&add%.d %f2,%0\"; +}") + +(define_expand "addsf3" + [(set (match_operand:SF 0 "general_operand" "") + (plus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (plus:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpadd%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpadd%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpadd3%.s %w2,%w1,%0\"; + return \"fpadd3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (float:SF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "f%$add%.l %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (float:SF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "f%$add%.w %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (float:SF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "f%$add%.b %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (plus:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"f%$add%.x %2,%0\"; + return \"f%$add%.s %f2,%0\"; +}") + +;; subtract instructions + +(define_insn "subdi_sexthishl32" + [(set (match_operand:DI 0 "general_operand" "=o,a,*d,*d") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") + (ashift:DI (sign_extend:DI (match_operand:HI 2 "general_operand" "rm,rm,rm,rm")) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=&d,X,a,?d"))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; + if (ADDRESS_REG_P (operands[0])) + return \"sub%.w %2,%0\"; + else if (ADDRESS_REG_P (operands[3])) + return \"move%.w %2,%3\;sub%.l %3,%0\"; + else + return \"move%.w %2,%3\;ext%.l %3\;sub%.l %3,%0\"; +} ") + +(define_insn "subdi_dishl32" + [(set (match_operand:DI 0 "general_operand" "+ro") + (minus:DI (match_dup 0) + (ashift:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32))))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[1]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else + operands[1] = adj_offsettable_operand (operands[1], 4); + return \"sub%.l %1,%0\"; +} ") + +(define_insn "subdi3" + [(set (match_operand:DI 0 "general_operand" "=<,o<>,d,d,d") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0,0") + (match_operand:DI 2 "general_operand" "<,d,no>,d,a"))) + (clobber (match_scratch:SI 3 "=X,&d,&d,X,&d"))] + "" + "* +{ + if (DATA_REG_P (operands[0])) + { + if (DATA_REG_P (operands[2])) + return \"sub%.l %R2,%R0\;subx%.l %2,%0\"; + else if (GET_CODE (operands[2]) == MEM + && GET_CODE (XEXP (operands[2], 0)) == POST_INC) + { + return \"move%.l %2,%3\;sub%.l %2,%R0\;subx%.l %3,%0\"; + } + else + { + rtx xoperands[2]; + if (GET_CODE (operands[2]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1); + else if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[2])); + } + else if (GET_CODE (operands[2]) == CONST_INT) + { + operands[1] = operands[2]; + operands[2] = INTVAL (operands[2]) < 0 ? constm1_rtx : const0_rtx; + } + else + operands[1] = adj_offsettable_operand (operands[2], 4); + xoperands[0] = operands[3]; + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 0) + xoperands[1] = GEN_INT (-INTVAL (operands[2]) - 1); + else + xoperands[1] = operands[2]; + output_asm_insn (output_move_simode (xoperands), xoperands); + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8) + { +#ifdef NO_ADDSUB_Q + return \"sub%.l %1,%R0\;subx%.l %3,%0\"; +#else + return \"subq%.l %1,%R0\;subx%.l %3,%0\"; +#endif + } + else if (INTVAL (operands[1]) >= -8 && INTVAL (operands[1]) < 0) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); +#ifdef NO_ADDSUB_Q + return \"add%.l %1,%R0\;addx%.l %3,%0\"; +#else + return \"addq%.l %1,%R0\;addx%.l %3,%0\"; +#endif + } + } + return \"sub%.l %1,%R0\;subx%.l %3,%0\"; + } + } + else if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (operands[2]) == MEM + && GET_CODE (XEXP (operands[2], 0)) == PRE_DEC) + return \"sub%.l %2,%0\;subx%.l %2,%0\"; + CC_STATUS_INIT; + if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + { + operands[1] + = gen_rtx_MEM (SImode, + gen_rtx_PLUS (VOIDmode, XEXP(operands[0], 0), + GEN_INT (-8))); + return \"move%.l %0,%3\;sub%.l %R2,%0\;subx%.l %2,%3\;move%.l %3,%1\"; + } + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + { + operands[1] = XEXP(operands[0], 0); + return \"sub%.l %R2,%0\;move%.l %0,%3\;subx%.l %2,%3\;move%.l %3,%1\"; + } + else + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"sub%.l %R2,%1\;move%.l %0,%3\;subx%.l %2,%3\;move%.l %3,%0\"; + } + } + else + abort (); +} ") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "general_operand" "=m,r") + (minus:SI (match_operand:SI 1 "general_operand" "0,0") + (match_operand:SI 2 "general_operand" "ds,mrs")))] + "" + "sub%.l %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (sign_extend:SI + (match_operand:HI 2 "nonimmediate_operand" "rm"))))] + "!TARGET_5200" + "sub%.w %2,%0") + +(define_insn "subhi3" + [(set (match_operand:HI 0 "general_operand" "=m,r") + (minus:HI (match_operand:HI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "dn,rmn")))] + "!TARGET_5200" + "sub%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (minus:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,rmn")))] + "!TARGET_5200" + "sub%.w %1,%0") + +(define_insn "subqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (minus:QI (match_operand:QI 1 "general_operand" "0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "sub%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (minus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "sub%.b %1,%0") + +(define_expand "subdf3" + [(set (match_operand:DF 0 "general_operand" "") + (minus:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,y,dmF") + (match_operand:DF 2 "general_operand" "xH,dmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.d %w2,%w1,%0\"; + return \"fpsub3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "f%&sub%.l %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%&sub%.w %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%&sub%.b %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (minus:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"f%&sub%.x %2,%0\"; + return \"f%&sub%.d %f2,%0\"; +}") + +(define_expand "subsf3" + [(set (match_operand:SF 0 "general_operand" "") + (minus:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprsub%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpsub%.s %w2,%0\"; + if (which_alternative == 0) + return \"fpsub3%.s %w2,%w1,%0\"; + return \"fpsub3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "f%$sub%.l %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%$sub%.w %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%$sub%.b %2,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (minus:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return \"f%$sub%.x %2,%0\"; + return \"f%$sub%.s %f2,%0\"; +}") + +;; multiply instructions + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "general_operand" "=d") + (mult:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dmn")))] + "" + "* +{ +#if defined(MOTOROLA) && !defined(CRDS) + return \"muls%.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "%0")) + (sign_extend:SI + (match_operand:HI 2 "nonimmediate_operand" "dm"))))] + "" + "* +{ +#if defined(MOTOROLA) && !defined(CRDS) + return \"muls%.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "%0")) + (match_operand:SI 2 "const_int_operand" "n")))] + "INTVAL (operands[2]) >= -0x8000 && INTVAL (operands[2]) <= 0x7fff" + "* +{ +#if defined(MOTOROLA) && !defined(CRDS) + return \"muls%.w %2,%0\"; +#else + return \"muls %2,%0\"; +#endif +}") + +(define_expand "mulsi3" + [(set (match_operand:SI 0 "general_operand" "") + (mult:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "TARGET_68020 || TARGET_5200" + "") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "dmsK")))] + "TARGET_68020" + "muls%.l %2,%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (match_operand:SI 1 "general_operand" "%0") + (match_operand:SI 2 "general_operand" "d<Q>")))] + "TARGET_5200" + "muls%.l %2,%0") + +(define_insn "umulhisi3" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "%0")) + (zero_extend:SI + (match_operand:HI 2 "nonimmediate_operand" "dm"))))] + "" + "* +{ +#if defined(MOTOROLA) && !defined(CRDS) + return \"mulu%.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "%0")) + (match_operand:SI 2 "const_int_operand" "n")))] + "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 0xffff" + "* +{ +#if defined(MOTOROLA) && !defined(CRDS) + return \"mulu%.w %2,%0\"; +#else + return \"mulu %2,%0\"; +#endif +}") + +;; We need a separate DEFINE_EXPAND for u?mulsidi3 to be able to use the +;; proper matching constraint. This is because the matching is between +;; the high-numbered word of the DImode operand[0] and operand[1]. +(define_expand "umulsidi3" + [(parallel + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 1) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (subreg:SI (match_dup 0) 0) + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (zero_extend:DI (match_dup 2))) + (const_int 32))))])] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "nonimmediate_operand" "dm"))) + (set (match_operand:SI 3 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (zero_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "mulu%.l %2,%3:%0") + +; Match immediate case. For 2.4 only match things < 2^31. +; It's tricky with larger values in these patterns since we need to match +; values between the two parallel multiplies, between a CONST_DOUBLE and +; a CONST_INT. +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "const_int_operand" "n"))) + (set (match_operand:SI 3 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (match_dup 2)) + (const_int 32))))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200 + && (unsigned) INTVAL (operands[2]) <= 0x7fffffff" + "mulu%.l %2,%3:%0") + +(define_expand "mulsidi3" + [(parallel + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 1) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (subreg:SI (match_dup 0) 0) + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (const_int 32))))])] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "nonimmediate_operand" "dm"))) + (set (match_operand:SI 3 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "muls%.l %2,%3:%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (mult:SI (match_operand:SI 1 "register_operand" "%0") + (match_operand:SI 2 "const_sint32_operand" ""))) + (set (match_operand:SI 3 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (match_dup 2)) + (const_int 32))))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "muls%.l %2,%3:%0") + +(define_expand "umulsi3_highpart" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "")) + (zero_extend:DI (match_operand:SI 2 "general_operand" ""))) + (const_int 32)))) + (clobber (match_dup 3))])] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + " +{ + operands[3] = gen_reg_rtx (SImode); + if (GET_CODE (operands[2]) == CONST_INT + || GET_CODE (operands[2]) == CONST_DOUBLE) + { + if (! const_uint32_operand (operands[2], VOIDmode)) + abort (); + /* We have to adjust the operand order for the matching constraints. */ + emit_insn (gen_const_umulsi3_highpart (operands[0], operands[3], + operands[1], operands[2])); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI (match_operand:SI 2 "register_operand" "%1")) + (zero_extend:DI (match_operand:SI 3 "nonimmediate_operand" "dm"))) + (const_int 32)))) + (clobber (match_operand:SI 1 "register_operand" "=d"))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "mulu%.l %3,%0:%1") + +(define_insn "const_umulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI (match_operand:SI 2 "register_operand" "1")) + (match_operand 3 "const_uint32_operand" "")) + (const_int 32)))) + (clobber (match_operand:SI 1 "register_operand" "=d"))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "mulu%.l %3,%0:%1") + +(define_expand "smulsi3_highpart" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "")) + (sign_extend:DI (match_operand:SI 2 "general_operand" ""))) + (const_int 32)))) + (clobber (match_dup 3))])] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + " +{ + operands[3] = gen_reg_rtx (SImode); + if (GET_CODE (operands[2]) == CONST_INT + || GET_CODE (operands[2]) == CONST_DOUBLE) + { + if (! const_sint32_operand (operands[2], VOIDmode)) + abort (); + /* We have to adjust the operand order for the matching constraints. */ + emit_insn (gen_const_smulsi3_highpart (operands[0], operands[3], + operands[1], operands[2])); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI (match_operand:SI 2 "register_operand" "%1")) + (sign_extend:DI (match_operand:SI 3 "nonimmediate_operand" "dm"))) + (const_int 32)))) + (clobber (match_operand:SI 1 "register_operand" "=d"))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "muls%.l %3,%0:%1") + +(define_insn "const_smulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI (match_operand:SI 2 "register_operand" "1")) + (match_operand 3 "const_sint32_operand" "")) + (const_int 32)))) + (clobber (match_operand:SI 1 "register_operand" "=d"))] + "TARGET_68020 && !TARGET_68060 && !TARGET_5200" + "muls%.l %3,%0:%1") + +(define_expand "muldf3" + [(set (match_operand:DF 0 "general_operand" "") + (mult:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (mult:DF (match_operand:DF 1 "general_operand" "%xH,y") + (match_operand:DF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.d %y2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.d %y1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.d %w2,%w1,%0\"; + return \"fpmul3%.d %x2,%x1,%0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (float:DF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&mul%.l %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (float:DF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&mul%.w %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (float:DF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:DF 1 "general_operand" "0")))] + "TARGET_68881" + "f%&mul%.b %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (mult:DF (match_operand:DF 1 "general_operand" "%0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (GET_CODE (operands[2]) == CONST_DOUBLE + && floating_exact_log2 (operands[2]) && !TARGET_68040 && !TARGET_68060) + { + int i = floating_exact_log2 (operands[2]); + operands[2] = GEN_INT (i); + return \"fscale%.l %2,%0\"; + } + if (REG_P (operands[2])) + return \"f%&mul%.x %2,%0\"; + return \"f%&mul%.d %f2,%0\"; +}") + +(define_expand "mulsf3" + [(set (match_operand:SF 0 "general_operand" "") + (mult:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (mult:SF (match_operand:SF 1 "general_operand" "%xH,y") + (match_operand:SF 2 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[1], operands[2])) + return \"fpsqr%.s %w1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpmul%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fpmul%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpmul3%.s %w2,%w1,%0\"; + return \"fpmul3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (float:SF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsmul%.l %2,%0\" + : \"fsglmul%.l %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (float:SF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsmul%.w %2,%0\" + : \"fsglmul%.w %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (float:SF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:SF 1 "general_operand" "0")))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsmul%.b %2,%0\" + : \"fsglmul%.b %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (mult:SF (match_operand:SF 1 "general_operand" "%0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ +#ifdef FSGLMUL_USE_S + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return (TARGET_68040_ONLY + ? \"fsmul%.s %2,%0\" + : \"fsglmul%.s %2,%0\"); +#else + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return (TARGET_68040_ONLY + ? \"fsmul%.x %2,%0\" + : \"fsglmul%.x %2,%0\"); +#endif + return (TARGET_68040_ONLY + ? \"fsmul%.s %f2,%0\" + : \"fsglmul%.s %f2,%0\"); +}") + +;; divide instructions + +(define_expand "divdf3" + [(set (match_operand:DF 0 "general_operand" "") + (div:DF (match_operand:DF 1 "general_operand" "") + (match_operand:DF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y,y") + (div:DF (match_operand:DF 1 "general_operand" "xH,y,rmF") + (match_operand:DF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.d %y1,%0\"; + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.d %y2,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.d %w2,%w1,%0\"; + return \"fpdiv3%.d %x2,%x1,%x0\"; +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "f%&div%.l %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%&div%.w %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (float:DF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "f%&div%.b %2,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (div:DF (match_operand:DF 1 "general_operand" "0") + (match_operand:DF 2 "general_operand" "fmG")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"f%&div%.x %2,%0\"; + return \"f%&div%.d %f2,%0\"; +}") + +(define_expand "divsf3" + [(set (match_operand:SF 0 "general_operand" "") + (div:SF (match_operand:SF 1 "general_operand" "") + (match_operand:SF 2 "general_operand" "")))] + "TARGET_68881 || TARGET_FPA" + "") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y,y") + (div:SF (match_operand:SF 1 "general_operand" "xH,y,rmF") + (match_operand:SF 2 "general_operand" "xH,rmF,0")))] + "TARGET_FPA" + "* +{ + if (rtx_equal_p (operands[0], operands[1])) + return \"fpdiv%.s %w2,%0\"; + if (rtx_equal_p (operands[0], operands[2])) + return \"fprdiv%.s %w1,%0\"; + if (which_alternative == 0) + return \"fpdiv3%.s %w2,%w1,%0\"; + return \"fpdiv3%.s %2,%1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsdiv%.l %2,%0\" + : \"fsgldiv%.l %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsdiv%.w %2,%0\" + : \"fsgldiv%.w %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (float:SF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "* +{ + return (TARGET_68040_ONLY + ? \"fsdiv%.b %2,%0\" + : \"fsgldiv%.b %2,%0\"); +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (div:SF (match_operand:SF 1 "general_operand" "0") + (match_operand:SF 2 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ +#ifdef FSGLDIV_USE_S + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return (TARGET_68040_ONLY + ? \"fsdiv%.s %2,%0\" + : \"fsgldiv%.s %2,%0\"); +#else + if (REG_P (operands[2]) && ! DATA_REG_P (operands[2])) + return (TARGET_68040_ONLY + ? \"fsdiv%.x %2,%0\" + : \"fsgldiv%.x %2,%0\"); +#endif + return (TARGET_68040_ONLY + ? \"fsdiv%.s %f2,%0\" + : \"fsgldiv%.s %f2,%0\"); +}") + +;; Remainder instructions. + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (div:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020 && !TARGET_5200" + "* +{ + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return \"divs%.l %2,%0\"; + else + return \"divsl%.l %2,%3:%0\"; +}") + +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "general_operand" "=d") + (udiv:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" "dmsK"))) + (set (match_operand:SI 3 "general_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "TARGET_68020 && !TARGET_5200" + "* +{ + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return \"divu%.l %2,%0\"; + else + return \"divul%.l %2,%3:%0\"; +}") + +(define_insn "divmodhi4" + [(set (match_operand:HI 0 "general_operand" "=d") + (div:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmsK"))) + (set (match_operand:HI 3 "general_operand" "=d") + (mod:HI (match_dup 1) (match_dup 2)))] + "!TARGET_5200" + "* +{ +#ifdef MOTOROLA + output_asm_insn (\"ext%.l %0\;divs%.w %2,%0\", operands); +#else + output_asm_insn (\"extl %0\;divs %2,%0\", operands); +#endif + if (!find_reg_note(insn, REG_UNUSED, operands[3])) + { + CC_STATUS_INIT; + return \"move%.l %0,%3\;swap %3\"; + } + else + return \"\"; +}") + +(define_insn "udivmodhi4" + [(set (match_operand:HI 0 "general_operand" "=d") + (udiv:HI (match_operand:HI 1 "general_operand" "0") + (match_operand:HI 2 "general_operand" "dmsK"))) + (set (match_operand:HI 3 "general_operand" "=d") + (umod:HI (match_dup 1) (match_dup 2)))] + "!TARGET_5200" + "* +{ +#ifdef MOTOROLA + output_asm_insn (\"and%.l %#0xFFFF,%0\;divu%.w %2,%0\", operands); +#else + output_asm_insn (\"and%.l %#0xFFFF,%0\;divu %2,%0\", operands); +#endif + if (!find_reg_note(insn, REG_UNUSED, operands[3])) + { + CC_STATUS_INIT; + return \"move%.l %0,%3\;swap %3\"; + } + else + return \"\"; +}") + +;; logical-and instructions + +;; "anddi3" is mainly here to help combine(). +(define_insn "anddi3" + [(set (match_operand:DI 0 "general_operand" "=o,d") + (and:DI (match_operand:DI 1 "general_operand" "%0,0") + (match_operand:DI 2 "general_operand" "dn,don")))] + "" + "* +{ + CC_STATUS_INIT; + /* We can get CONST_DOUBLE, but also const1_rtx etc. */ + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[2]) == CONST_INT) + { + rtx hi, lo; + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + hi = GEN_INT (CONST_DOUBLE_HIGH (operands[2])); + lo = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + } + else + { + lo = operands[2]; + hi = INTVAL (lo) < 0 ? constm1_rtx : const0_rtx; + } + switch (INTVAL (hi)) + { + case 0 : + output_asm_insn (\"clr%.l %0\", operands); + break; + case -1 : + break; + default : + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = hi; + output_asm_insn (output_andsi3 (xoperands), xoperands); + } + } + if (GET_CODE (operands[0]) == REG) + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[0] = adj_offsettable_operand (operands[0], 4); + switch (INTVAL (lo)) + { + case 0 : + output_asm_insn (\"clr%.l %0\", operands); + break; + case -1 : + break; + default : + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = lo; + output_asm_insn (output_andsi3 (xoperands), xoperands); + } + } + return \"\"; + } + if (GET_CODE (operands[0]) != REG) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"and%.l %2,%0\;and%.l %R2,%1\"; + } + if (GET_CODE (operands[2]) != REG) + { + operands[1] = adj_offsettable_operand (operands[2], 4); + return \"and%.l %2,%0\;and%.l %1,%R0\"; + } + return \"and%.l %2,%0\;and%.l %R2,%R0\"; +}") + +;; Prevent AND from being made with sp. This doesn't exist in the machine +;; and reload will cause inefficient code. Since sp is a FIXED_REG, we +;; can't allocate pseudos into it. + +(define_expand "andsi3" + [(set (match_operand:SI 0 "not_sp_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmMs")))] + "" + "") + +(define_insn "andsi3_internal" + [(set (match_operand:SI 0 "not_sp_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmMs")))] + "!TARGET_5200" + "* +{ + return output_andsi3 (operands); +}") + +(define_insn "andsi3_5200" + [(set (match_operand:SI 0 "not_sp_operand" "=m,d") + (and:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "d,dmsK")))] + "TARGET_5200" + "and%.l %2,%0") + +(define_insn "andhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (and:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "and%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (and:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "and%.w %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (and:HI (match_operand:HI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "!TARGET_5200" + "and%.w %1,%0") + +(define_insn "andqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (and:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "and%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (and:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "and%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (and:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "!TARGET_5200" + "and%.b %1,%0") + +;; inclusive-or instructions + +(define_insn "iordi_zext" + [(set (match_operand:DI 0 "general_operand" "=o,d") + (ior:DI (zero_extend:DI (match_operand 1 "general_operand" "dn,dmn")) + (match_operand:DI 2 "general_operand" "0,0")))] + "!TARGET_5200" + "* +{ + int byte_mode; + + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else + operands[0] = adj_offsettable_operand (operands[0], 4); + if (GET_MODE (operands[1]) == SImode) + return \"or%.l %1,%0\"; + byte_mode = (GET_MODE (operands[1]) == QImode); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], byte_mode ? 3 : 2); + if (byte_mode) + return \"or%.b %1,%0\"; + else + return \"or%.w %1,%0\"; +}") + +;; "iordi3" is mainly here to help combine(). +(define_insn "iordi3" + [(set (match_operand:DI 0 "general_operand" "=o,d") + (ior:DI (match_operand:DI 1 "general_operand" "%0,0") + (match_operand:DI 2 "general_operand" "dn,don")))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; + /* We can get CONST_DOUBLE, but also const1_rtx etc. */ + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[2]) == CONST_INT) + { + rtx hi, lo; + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + hi = GEN_INT (CONST_DOUBLE_HIGH (operands[2])); + lo = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + } + else + { + lo = operands[2]; + hi = INTVAL (lo) < 0 ? constm1_rtx : const0_rtx; + } + switch (INTVAL (hi)) + { + case 0 : + break; + case -1 : + /* FIXME : a scratch register would be welcome here if operand[0] + is not a register */ + output_asm_insn (\"move%.l %#-1,%0\", operands); + break; + default : + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = hi; + output_asm_insn (output_iorsi3 (xoperands), xoperands); + } + } + if (GET_CODE (operands[0]) == REG) + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[0] = adj_offsettable_operand (operands[0], 4); + switch (INTVAL (lo)) + { + case 0 : + break; + case -1 : + /* FIXME : a scratch register would be welcome here if operand[0] + is not a register */ + output_asm_insn (\"move%.l %#-1,%R0\", operands); + break; + default : + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = lo; + output_asm_insn (output_iorsi3 (xoperands), xoperands); + } + } + return \"\"; + } + if (GET_CODE (operands[0]) != REG) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"or%.l %2,%0\;or%.l %R2,%1\"; + } + if (GET_CODE (operands[2]) != REG) + { + operands[1] = adj_offsettable_operand (operands[2], 4); + return \"or%.l %2,%0\;or%.l %1,%R0\"; + } + return \"or%.l %2,%0\;or%.l %R2,%R0\"; +}") + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "general_operand" "") + (ior:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + +(define_insn "iorsi3_internal" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "dKs,dmMs")))] + "! TARGET_5200" + "* +{ + return output_iorsi3 (operands); +}") + +(define_insn "iorsi3_5200" + [(set (match_operand:SI 0 "general_operand" "=m,d") + (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "d,dmsK")))] + "TARGET_5200" + "or%.l %2,%0") + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "general_operand" "=m,d") + (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "or%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (ior:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "or%.w %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+m,d")) + (ior:HI (match_operand:HI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "!TARGET_5200" + "or%.w %1,%0") + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "general_operand" "=m,d") + (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + (match_operand:QI 2 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "or%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (ior:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn,dmn")))] + "!TARGET_5200" + "or%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+m,d")) + (ior:QI (match_operand:QI 1 "general_operand" "dn,dmn") + (match_dup 0)))] + "!TARGET_5200" + "or%.b %1,%0") + +;; On all 68k models, this makes faster code in a special case. +;; See also ashlsi_16, ashrsi_16 and lshrsi_16. + +(define_insn "iorsi_zexthi_ashl16" + [(set (match_operand:SI 0 "general_operand" "=&d") + (ior:SI (zero_extend:SI (match_operand:HI 1 "general_operand" "rmn")) + (ashift:SI (match_operand:SI 2 "general_operand" "or") + (const_int 16))))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[2]) != REG) + operands[2] = adj_offsettable_operand (operands[2], 2); + if (GET_CODE (operands[2]) != REG + || REGNO (operands[2]) != REGNO (operands[0])) + output_asm_insn (\"move%.w %2,%0\", operands); + return \"swap %0\;mov%.w %1,%0\"; +}") + +(define_insn "iorsi_zext" + [(set (match_operand:SI 0 "general_operand" "=o,d") + (ior:SI (zero_extend:SI (match_operand 1 "general_operand" "dn,dmn")) + (match_operand:SI 2 "general_operand" "0,0")))] + "!TARGET_5200" + "* +{ + int byte_mode; + + CC_STATUS_INIT; + byte_mode = (GET_MODE (operands[1]) == QImode); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], byte_mode ? 3 : 2); + if (byte_mode) + return \"or%.b %1,%0\"; + else + return \"or%.w %1,%0\"; +}") + +;; xor instructions + +;; "xordi3" is mainly here to help combine(). +(define_insn "xordi3" + [(set (match_operand:DI 0 "general_operand" "=od") + (xor:DI (match_operand:DI 1 "general_operand" "%0") + (match_operand:DI 2 "general_operand" "dn")))] + "" + "* +{ + CC_STATUS_INIT; + /* We can get CONST_DOUBLE, but also const1_rtx etc. */ + if (GET_CODE (operands[2]) == CONST_DOUBLE + || GET_CODE (operands[2]) == CONST_INT) + { + rtx hi, lo; + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + hi = GEN_INT (CONST_DOUBLE_HIGH (operands[2])); + lo = GEN_INT (CONST_DOUBLE_LOW (operands[2])); + } + else + { + lo = operands[2]; + hi = INTVAL (lo) < 0 ? constm1_rtx : const0_rtx; + } + switch (INTVAL (hi)) + { + case 0 : + break; + case -1 : + output_asm_insn (\"not%.l %0\", operands); + break; + default : + /* FIXME : a scratch register would be welcome here if + -128 <= INTVAL (hi) < -1 */ + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = hi; + output_asm_insn (output_xorsi3 (xoperands), xoperands); + } + } + if (GET_CODE (operands[0]) == REG) + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[0] = adj_offsettable_operand (operands[0], 4); + switch (INTVAL (lo)) + { + case 0 : + break; + case -1 : + output_asm_insn (\"not%.l %0\", operands); + break; + default : + /* FIXME : a scratch register would be welcome here if + -128 <= INTVAL (lo) < -1 */ + operands[2] = lo; + /* FIXME : this should be merged with xorsi3 */ + { + rtx xoperands[3]; + + xoperands[0] = operands[0]; + xoperands[2] = lo; + output_asm_insn (output_xorsi3 (xoperands), xoperands); + } + } + return \"\"; + } + if (GET_CODE (operands[0]) != REG) + { + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"eor%.l %2,%0\;eor%.l %R2,%1\"; + } + if (GET_CODE (operands[2]) != REG) + { + operands[1] = adj_offsettable_operand (operands[2], 4); + return \"eor%.l %2,%0\;eor%.l %1,%R0\"; + } + return \"eor%.l %2,%0\;eor%.l %R2,%R0\"; +}") + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "general_operand" "") + (xor:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + +(define_insn "xorsi3_internal" + [(set (match_operand:SI 0 "general_operand" "=do,m") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "di,dKs")))] + "!TARGET_5200" + "* +{ + return output_xorsi3 (operands); +}") + +(define_insn "xorsi3_5200" + [(set (match_operand:SI 0 "general_operand" "=dm,d") + (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + (match_operand:SI 2 "general_operand" "d,Ks")))] + "TARGET_5200" + "eor%.l %2,%0") + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "general_operand" "=dm") + (xor:HI (match_operand:HI 1 "general_operand" "%0") + (match_operand:HI 2 "general_operand" "dn")))] + "!TARGET_5200" + "eor%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (xor:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dn")))] + "!TARGET_5200" + "eor%.w %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (xor:HI (match_operand:HI 1 "general_operand" "dn") + (match_dup 0)))] + "!TARGET_5200" + "eor%.w %1,%0") + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "general_operand" "=dm") + (xor:QI (match_operand:QI 1 "general_operand" "%0") + (match_operand:QI 2 "general_operand" "dn")))] + "!TARGET_5200" + "eor%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (xor:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dn")))] + "!TARGET_5200" + "eor%.b %1,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (xor:QI (match_operand:QI 1 "general_operand" "dn") + (match_dup 0)))] + "!TARGET_5200" + "eor%.b %1,%0") + +;; negation instructions + +(define_expand "negdi2" + [(set (match_operand:DI 0 "general_operand" "") + (neg:DI (match_operand:DI 1 "general_operand" "")))] + "" + " +{ + if (TARGET_5200) + emit_insn (gen_negdi2_5200 (operands[0], operands[1])); + else + emit_insn (gen_negdi2_internal (operands[0], operands[1])); + DONE; +}") + +(define_insn "negdi2_internal" + [(set (match_operand:DI 0 "general_operand" "=<,do,!*a") + (neg:DI (match_operand:DI 1 "general_operand" "0,0,0")))] + "!TARGET_5200" + "* +{ + if (which_alternative == 0) + return \"neg%.l %0\;negx%.l %0\"; + if (GET_CODE (operands[0]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[1] = adj_offsettable_operand (operands[0], 4); + if (ADDRESS_REG_P (operands[0])) + return \"exg %/d0,%1\;neg%.l %/d0\;exg %/d0,%1\;exg %/d0,%0\;negx%.l %/d0\;exg %/d0,%0\"; + else + return \"neg%.l %1\;negx%.l %0\"; +} ") + +(define_insn "negdi2_5200" + [(set (match_operand:DI 0 "general_operand" "=d") + (neg:DI (match_operand:DI 1 "general_operand" "0")))] + "TARGET_5200" + "* +{ + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"neg%.l %1\;negx%.l %0\"; +} ") + +(define_expand "negsi2" + [(set (match_operand:SI 0 "general_operand" "") + (neg:SI (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + if (TARGET_5200) + emit_insn (gen_negsi2_5200 (operands[0], operands[1])); + else + emit_insn (gen_negsi2_internal (operands[0], operands[1])); + DONE; +}") + +(define_insn "negsi2_internal" + [(set (match_operand:SI 0 "general_operand" "=dm") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "!TARGET_5200" + "neg%.l %0") + +(define_insn "negsi2_5200" + [(set (match_operand:SI 0 "general_operand" "=d") + (neg:SI (match_operand:SI 1 "general_operand" "0")))] + "TARGET_5200" + "neg%.l %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (neg:HI (match_operand:HI 1 "general_operand" "0")))] + "!TARGET_5200" + "neg%.w %0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (neg:HI (match_dup 0)))] + "!TARGET_5200" + "neg%.w %0") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (neg:QI (match_operand:QI 1 "general_operand" "0")))] + "!TARGET_5200" + "neg%.b %0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (neg:QI (match_dup 0)))] + "!TARGET_5200" + "neg%.b %0") + +;; If using software floating point, just flip the sign bit. + +(define_expand "negsf2" + [(set (match_operand:SF 0 "general_operand" "") + (neg:SF (match_operand:SF 1 "general_operand" "")))] + "" + " +{ + if (!TARGET_FPA && !TARGET_68881) + { + rtx result; + rtx target; + + target = operand_subword_force (operands[0], 0, SFmode); + result = expand_binop (SImode, xor_optab, + operand_subword_force (operands[1], 0, SFmode), + GEN_INT(0x80000000), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + /* Make a place for REG_EQUAL. */ + emit_move_insn (operands[0], operands[0]); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (neg:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.s %w1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f,d") + (neg:SF (match_operand:SF 1 "general_operand" "fdmF,0")))] + "TARGET_68881" + "* +{ + if (DATA_REG_P (operands[0])) + { + operands[1] = GEN_INT (31); + return \"bchg %1,%0\"; + } + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"f%$neg%.x %1,%0\"; + return \"f%$neg%.s %f1,%0\"; +}") + +(define_expand "negdf2" + [(set (match_operand:DF 0 "general_operand" "") + (neg:DF (match_operand:DF 1 "general_operand" "")))] + "" + " +{ + if (!TARGET_FPA && !TARGET_68881) + { + rtx result; + rtx target; + rtx insns; + + start_sequence (); + target = operand_subword (operands[0], 0, 1, DFmode); + result = expand_binop (SImode, xor_optab, + operand_subword_force (operands[1], 0, DFmode), + GEN_INT(0x80000000), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + emit_move_insn (operand_subword (operands[0], 1, 1, DFmode), + operand_subword_force (operands[1], 1, DFmode)); + + insns = get_insns (); + end_sequence (); + + emit_no_conflict_block (insns, operands[0], operands[1], 0, 0); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (neg:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpneg%.d %y1, %0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f,d") + (neg:DF (match_operand:DF 1 "general_operand" "fmF,0")))] + "TARGET_68881" + "* +{ + if (DATA_REG_P (operands[0])) + { + operands[1] = GEN_INT (31); + return \"bchg %1,%0\"; + } + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"f%&neg%.x %1,%0\"; + return \"f%&neg%.d %f1,%0\"; +}") + +;; Sqrt instruction for the 68881 + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (sqrt:SF (match_operand:SF 1 "general_operand" "fm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"f%$sqrt%.x %1,%0\"; + else + return \"f%$sqrt%.s %1,%0\"; +}") + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (sqrt:DF (match_operand:DF 1 "general_operand" "fm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"f%&sqrt%.x %1,%0\"; + else + return \"f%&sqrt%.d %1,%0\"; +}") + +;; Absolute value instructions +;; If using software floating point, just zero the sign bit. + +(define_expand "abssf2" + [(set (match_operand:SF 0 "general_operand" "") + (abs:SF (match_operand:SF 1 "general_operand" "")))] + "" + " +{ + if (!TARGET_FPA && !TARGET_68881) + { + rtx result; + rtx target; + + target = operand_subword_force (operands[0], 0, SFmode); + result = expand_binop (SImode, and_optab, + operand_subword_force (operands[1], 0, SFmode), + GEN_INT(0x7fffffff), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + /* Make a place for REG_EQUAL. */ + emit_move_insn (operands[0], operands[0]); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=x,y") + (abs:SF (match_operand:SF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.s %y1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=f") + (abs:SF (match_operand:SF 1 "general_operand" "fdmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"f%$abs%.x %1,%0\"; + return \"f%$abs%.s %f1,%0\"; +}") + +(define_expand "absdf2" + [(set (match_operand:DF 0 "general_operand" "") + (abs:DF (match_operand:DF 1 "general_operand" "")))] + "" + " +{ + if (!TARGET_FPA && !TARGET_68881) + { + rtx result; + rtx target; + rtx insns; + + start_sequence (); + target = operand_subword (operands[0], 0, 1, DFmode); + result = expand_binop (SImode, and_optab, + operand_subword_force (operands[1], 0, DFmode), + GEN_INT(0x7fffffff), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + emit_move_insn (operand_subword (operands[0], 1, 1, DFmode), + operand_subword_force (operands[1], 1, DFmode)); + + insns = get_insns (); + end_sequence (); + + emit_no_conflict_block (insns, operands[0], operands[1], 0, 0); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=x,y") + (abs:DF (match_operand:DF 1 "general_operand" "xH,rmF")))] + "TARGET_FPA" + "fpabs%.d %y1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "general_operand" "=f") + (abs:DF (match_operand:DF 1 "general_operand" "fmF")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"f%&abs%.x %1,%0\"; + return \"f%&abs%.d %f1,%0\"; +}") + +;; one complement instructions + +;; "one_cmpldi2" is mainly here to help combine(). +(define_insn "one_cmpldi2" + [(set (match_operand:DI 0 "general_operand" "=dm") + (not:DI (match_operand:DI 1 "general_operand" "0")))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC + || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + operands[1] = operands[0]; + else + operands[1] = adj_offsettable_operand (operands[0], 4); + return \"not%.l %1\;not%.l %0\"; +}") + +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "general_operand" "") + (not:SI (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + if (TARGET_5200) + emit_insn (gen_one_cmplsi2_5200 (operands[0], operands[1])); + else + emit_insn (gen_one_cmplsi2_internal (operands[0], operands[1])); + DONE; +}") + +(define_insn "one_cmplsi2_internal" + [(set (match_operand:SI 0 "general_operand" "=dm") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "!TARGET_5200" + "not%.l %0") + +(define_insn "one_cmplsi2_5200" + [(set (match_operand:SI 0 "general_operand" "=d") + (not:SI (match_operand:SI 1 "general_operand" "0")))] + "TARGET_5200" + "not%.l %0") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (not:HI (match_operand:HI 1 "general_operand" "0")))] + "!TARGET_5200" + "not%.w %0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+dm")) + (not:HI (match_dup 0)))] + "!TARGET_5200" + "not%.w %0") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (not:QI (match_operand:QI 1 "general_operand" "0")))] + "!TARGET_5200" + "not%.b %0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+dm")) + (not:QI (match_dup 0)))] + "!TARGET_5200" + "not%.b %0") + +;; arithmetic shift instructions +;; We don't need the shift memory by 1 bit instruction + +(define_insn "ashldi_extsi" + [(set (match_operand:DI 0 "general_operand" "=ro") + (ashift:DI + (match_operator:DI 2 "extend_operator" + [(match_operand:SI 1 "general_operand" "rm")]) + (const_int 32)))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[2] = adj_offsettable_operand (operands[0], 4); + if (ADDRESS_REG_P (operands[0])) + return \"move%.l %1,%0\;sub%.l %2,%2\"; + else + return \"move%.l %1,%0\;clr%.l %2\"; +} ") + +(define_insn "ashldi_sexthi" + [(set (match_operand:DI 0 "general_operand" "=m,a*d") + (ashift:DI (sign_extend:DI (match_operand:HI 1 "general_operand" "rm,rm")) + (const_int 32))) + (clobber (match_scratch:SI 2 "=a,X"))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == MEM) + { + if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"clr%.l %0\;move%.w %1,%2\;move%.l %2,%0\"; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"move%.w %1,%2\;move%.l %2,%0\;clr%.l %0\"; + else + { + operands[3] = adj_offsettable_operand (operands[0], 4); + return \"move%.w %1,%2\;move%.l %2,%0\;clr%.l %3\"; + } + } + else if (DATA_REG_P (operands[0])) + return \"move%.w %1,%0\;ext%.l %0\;clr%.l %R0\"; + else + return \"move%.w %1,%0\;sub%.l %R0,%R0\"; +} ") + +(define_insn "ashldi_const32" + [(set (match_operand:DI 0 "general_operand" "=rm") + (ashift:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32)))] + "" + "* +{ + CC_STATUS_INIT; + if (GET_CODE (operands[1]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else + operands[3] = adj_offsettable_operand (operands[1], 4); + if (GET_CODE (operands[0]) == REG) + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + return \"clr%.l %0\;move%.l %3,%0\"; + else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) + return \"move%.l %3,%0\;clr%.l %0\"; + else + operands[2] = adj_offsettable_operand (operands[0], 4); + if (ADDRESS_REG_P (operands[2])) + return \"move%.l %3,%0\;sub%.l %2,%2\"; + else + return \"move%.l %3,%0\;clr%.l %2\"; +} ") + +;; The predicate below must be general_operand, because ashldi3 allows that +(define_insn "ashldi_const" + [(set (match_operand:DI 0 "general_operand" "=d") + (ashift:DI (match_operand:DI 1 "general_operand" "0") + (match_operand 2 "const_int_operand" "n")))] + "(!TARGET_5200 + && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3) + || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16 + || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63)))" + "* +{ + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (INTVAL (operands[2]) == 1) + return \"add%.l %1,%1\;addx%.l %0,%0\"; + else if (INTVAL (operands[2]) == 8) + return \"rol%.l %#8,%1\;rol%.l %#8,%0\;move%.b %1,%0\;clr%.b %1\"; + else if (INTVAL (operands[2]) == 16) + return \"swap %1\;swap %0\;move%.w %1,%0\;clr%.w %1\"; + else if (INTVAL (operands[2]) == 48) + return \"mov%.l %1,%0\;swap %0\;clr%.l %1\;clr%.w %0\"; + else if (INTVAL (operands[2]) == 2) + return \"add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0\"; + else if (INTVAL (operands[2]) == 3) + return \"add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0\;add%.l %1,%1\;addx%.l %0,%0\"; + else /* 32 < INTVAL (operands[2]) <= 63 */ + { + operands[2] = GEN_INT (INTVAL (operands[2]) - 32); + output_asm_insn (INTVAL (operands[2]) <= 8 ? \"asl%.l %2,%1\" : + \"moveq %2,%0\;asl%.l %0,%1\", operands); + return \"mov%.l %1,%0\;moveq %#0,%1\"; + } +} ") + +(define_expand "ashldi3" + [(set (match_operand:DI 0 "general_operand" "") + (ashift:DI (match_operand:DI 1 "general_operand" "") + (match_operand 2 "const_int_operand" "")))] + "!TARGET_5200" + " +{ + /* ??? This is a named pattern like this is not allowed to FAIL based + on its operands. */ + if (GET_CODE (operands[2]) != CONST_INT + || ((INTVAL (operands[2]) < 1 || INTVAL (operands[2]) > 3) + && INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16 + && (INTVAL (operands[2]) < 32 || INTVAL (operands[2]) > 63))) + FAIL; +} ") + +;; On most 68k models, this makes faster code in a special case. + +(define_insn "ashlsi_16" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (const_int 16)))] + "!TARGET_68060" + "* +{ + CC_STATUS_INIT; + return \"swap %0\;clr%.w %0\"; +}") + +;; ashift patterns : use lsl instead of asl, because lsl always clears the +;; overflow bit, so we must not set CC_NO_OVERFLOW. + +;; On the 68000, this makes faster code in a special case. + +(define_insn "ashlsi_17_24" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_int_operand" "n")))] + "(! TARGET_68020 && !TARGET_5200 + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" + "* +{ + CC_STATUS_INIT; + + operands[2] = GEN_INT (INTVAL (operands[2]) - 16); + return \"lsl%.w %2,%0\;swap %0\;clr%.w %0\"; +}") + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "* +{ + if (operands[2] == const1_rtx) + { + cc_status.flags = CC_NO_OVERFLOW; + return \"add%.l %0,%0\"; + } + return \"lsl%.l %2,%0\"; +}") + +(define_insn "ashlhi3" + [(set (match_operand:HI 0 "register_operand" "=d") + (ashift:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "!TARGET_5200" + "lsl%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (ashift:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "!TARGET_5200" + "lsl%.w %1,%0") + +(define_insn "ashlqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (ashift:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "!TARGET_5200" + "lsl%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (ashift:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "!TARGET_5200" + "lsl%.b %1,%0") + +;; On most 68k models, this makes faster code in a special case. + +(define_insn "ashrsi_16" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (const_int 16)))] + "!TARGET_68060" + "swap %0\;ext%.l %0") + +;; On the 68000, this makes faster code in a special case. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_int_operand" "n")))] + "(! TARGET_68020 && !TARGET_5200 + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" + "* +{ + operands[2] = GEN_INT (INTVAL (operands[2]) - 16); + return \"swap %0\;asr%.w %2,%0\;ext%.l %0\"; +}") + +(define_insn "subreghi1ashrdi_const32" + [(set (match_operand:HI 0 "general_operand" "=rm") + (subreg:HI (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32)) 1))] + "" + "* +{ + if (GET_CODE (operands[1]) != REG) + operands[1] = adj_offsettable_operand (operands[1], 2); + return \"move%.w %1,%0\"; +} ") + +(define_insn "subregsi1ashrdi_const32" + [(set (match_operand:SI 0 "general_operand" "=rm") + (subreg:SI (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32)) 1))] + "" + "* +{ + return \"move%.l %1,%0\"; +} ") + +(define_insn "ashrdi_const32" + [(set (match_operand:DI 0 "register_operand" "=d") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32)))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (TARGET_68020) + return \"move%.l %1,%2\;smi %0\;extb%.l %0\"; + else + return \"move%.l %1,%2\;smi %0\;ext%.w %0\;ext%.l %0\"; +} ") + +(define_insn "ashrdi_const32_mem" + [(set (match_operand:DI 0 "general_operand" "=o,<") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro,ro") + (const_int 32))) + (clobber (match_scratch:SI 2 "=d,d"))] + "" + "* +{ + CC_STATUS_INIT; + if (which_alternative == 1) + operands[3] = operands[0]; + else + operands[3] = adj_offsettable_operand (operands[0], 4); + if (TARGET_68020) + return \"move%.l %1,%3\;smi %2\;extb%.l %2\;move%.l %2,%0\"; + else + return \"move%.l %1,%3\;smi %2\;ext%.w %2\;ext%.l %2\;move%.l %2,%0\"; +} ") + +;; The predicate below must be general_operand, because ashrdi3 allows that +(define_insn "ashrdi_const" + [(set (match_operand:DI 0 "general_operand" "=d") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "0") + (match_operand 2 "const_int_operand" "n")))] + "!TARGET_5200 + && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3) + || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16 + || INTVAL (operands[2]) == 31 + || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63))" + "* +{ + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (INTVAL (operands[2]) == 63) + return \"add%.l %0,%0\;subx%.l %0,%0\;move%.l %0,%1\"; + CC_STATUS_INIT; + if (INTVAL (operands[2]) == 1) + return \"asr%.l %#1,%0\;roxr%.l %#1,%1\"; + else if (INTVAL (operands[2]) == 8) + return \"move%.b %0,%1\;asr%.l %#8,%0\;ror%.l %#8,%1\"; + else if (INTVAL (operands[2]) == 16) + return \"move%.w %0,%1\;clr%.w %0\;swap %1\;ext%.l %0\"; + else if (INTVAL (operands[2]) == 48) + return \"swap %0\;ext%.l %0\;move%.l %0,%1\;smi %0\;ext%.w %0\"; + else if (INTVAL (operands[2]) == 31) + return \"add%.l %1,%1\;addx%.l %0,%0\;move%.l %0,%1\;subx%.l %0,%0\"; + else if (INTVAL (operands[2]) == 2) + return \"asr%.l %#1,%0\;roxr%.l %#1,%1\;asr%.l %#1,%0\;roxr%.l %#1,%1\"; + else if (INTVAL (operands[2]) == 3) + return \"asr%.l %#1,%0\;roxr%.l %#1,%1\;asr%.l %#1,%0\;roxr%.l %#1,%1\;asr%.l %#1,%0\;roxr%.l %#1,%1\"; + else /* 32 < INTVAL (operands[2]) <= 63 */ + { + operands[2] = GEN_INT (INTVAL (operands[2]) - 32); + output_asm_insn (INTVAL (operands[2]) <= 8 ? \"asr%.l %2,%0\" : + \"moveq %2,%1\;asr%.l %1,%0\", operands); + output_asm_insn (\"mov%.l %0,%1\;smi %0\", operands); + return INTVAL (operands[2]) >= 15 ? \"ext%.w %d0\" : + TARGET_68020 ? \"extb%.l %0\" : \"ext%.w %0\;ext%.l %0\"; + } +} ") + +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "general_operand" "") + (ashiftrt:DI (match_operand:DI 1 "general_operand" "") + (match_operand 2 "const_int_operand" "")))] + "!TARGET_5200" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ((INTVAL (operands[2]) < 1 || INTVAL (operands[2]) > 3) + && INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16 + && (INTVAL (operands[2]) < 31 || INTVAL (operands[2]) > 63))) + FAIL; +} ") + +;; On all 68k models, this makes faster code in a special case. + +(define_insn "ashrsi_31" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (const_int 31)))] + "" + "* +{ + return \"add%.l %0,%0\;subx%.l %0,%0\"; +}") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "asr%.l %2,%0") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "register_operand" "=d") + (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "!TARGET_5200" + "asr%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (ashiftrt:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "!TARGET_5200" + "asr%.w %1,%0") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "!TARGET_5200" + "asr%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (ashiftrt:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "!TARGET_5200" + "asr%.b %1,%0") + +;; logical shift instructions + +;; commented out because of reload problems in 950612-1.c +;;(define_insn "" +;; [(set (cc0) +;; (subreg:SI (lshiftrt:DI (match_operand:DI 0 "general_operand" "ro") +;; (const_int 32)) 1)) +;; (set (match_operand:SI 1 "general_operand" "=dm") +;; (subreg:SI (lshiftrt:DI (match_dup 0) +;; (const_int 32)) 1))] +;; "" +;; "* +;;{ +;; return \"move%.l %0,%1\"; +;;} ") +;; +;;(define_insn "" +;; [(set (cc0) +;; (subreg:SI (lshiftrt:DI (match_operand:DI 0 "general_operand" "ro") +;; (const_int 32)) 0)) +;; (set (match_operand:DI 1 "general_operand" "=do") +;; (lshiftrt:DI (match_dup 0) +;; (const_int 32)))] +;; "" +;; "* +;;{ +;; if (GET_CODE (operands[1]) == REG) +;; operands[2] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); +;; else +;; operands[2] = adj_offsettable_operand (operands[1], 4); +;; return \"move%.l %0,%2\;clr%.l %1\"; +;;} ") + +(define_insn "subreg1lshrdi_const32" + [(set (match_operand:SI 0 "general_operand" "=rm") + (subreg:SI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro") + (const_int 32)) 1))] + "" + "* +{ + return \"move%.l %1,%0\"; +} ") + +(define_insn "lshrdi_const32" + [(set (match_operand:DI 0 "general_operand" "=ro,<,>") + (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro,ro,ro") + (const_int 32)))] + "" + "* +{ + CC_STATUS_INIT; + if (which_alternative == 1) + return \"move%.l %1,%0\;clr%.l %0\"; + if (which_alternative == 2) + return \"clr%.l %0\;move%.l %1,%0\"; + if (GET_CODE (operands[0]) == REG) + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[2] = adj_offsettable_operand (operands[0], 4); + if (GET_CODE (operands[1]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else + operands[3] = adj_offsettable_operand (operands[1], 4); + if (ADDRESS_REG_P (operands[0])) + return \"move%.l %1,%2\;sub%.l %0,%0\"; + else + return \"move%.l %1,%2\;clr%.l %0\"; +} ") + +;; The predicate below must be general_operand, because lshrdi3 allows that +(define_insn "lshrdi_const" + [(set (match_operand:DI 0 "general_operand" "=d") + (lshiftrt:DI (match_operand:DI 1 "general_operand" "0") + (match_operand 2 "const_int_operand" "n")))] + "!TARGET_5200 + && ((INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3) + || INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16 + || (INTVAL (operands[2]) > 32 && INTVAL (operands[2]) <= 63))" + "* +{ + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + if (INTVAL (operands[2]) == 63) + return \"add%.l %0,%0\;clr%.l %0\;clr%.l %1\;addx%.l %1,%1\"; + CC_STATUS_INIT; + if (INTVAL (operands[2]) == 1) + return \"lsr%.l %#1,%0\;roxr%.l %#1,%1\"; + else if (INTVAL (operands[2]) == 8) + return \"move%.b %0,%1\;lsr%.l %#8,%0\;ror%.l %#8,%1\"; + else if (INTVAL (operands[2]) == 16) + return \"move%.w %0,%1\;clr%.w %0\;swap %1\;swap %0\"; + else if (INTVAL (operands[2]) == 48) + return \"move%.l %0,%1\;clr%.w %1\;clr%.l %0\;swap %1\"; + else if (INTVAL (operands[2]) == 2) + return \"lsr%.l %#1,%0\;roxr%.l %#1,%1\;lsr%.l %#1,%0\;roxr%.l %#1,%1\"; + else if (INTVAL (operands[2]) == 3) + return \"lsr%.l %#1,%0\;roxr%.l %#1,%1\;lsr%.l %#1,%0\;roxr%.l %#1,%1\;lsr%.l %#1,%0\;roxr%.l %#1,%1\"; + else /* 32 < INTVAL (operands[2]) <= 63 */ + { + operands[2] = GEN_INT (INTVAL (operands[2]) - 32); + output_asm_insn (INTVAL (operands[2]) <= 8 ? \"lsr%.l %2,%0\" : + \"moveq %2,%1\;lsr%.l %1,%0\", operands); + return \"mov%.l %0,%1\;moveq %#0,%0\"; + } +} ") + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "general_operand" "") + (lshiftrt:DI (match_operand:DI 1 "general_operand" "") + (match_operand 2 "const_int_operand" "")))] + "!TARGET_5200" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ((INTVAL (operands[2]) < 1 || INTVAL (operands[2]) > 3) + && INTVAL (operands[2]) != 8 && INTVAL (operands[2]) != 16 + && (INTVAL (operands[2]) < 32 || INTVAL (operands[2]) > 63))) + FAIL; +} ") + +;; On all 68k models, this makes faster code in a special case. + +(define_insn "lshrsi_31" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (const_int 31)))] + "" + "* +{ + return \"add%.l %0,%0\;subx%.l %0,%0\;neg%.l %0\"; +}") + +;; On most 68k models, this makes faster code in a special case. + +(define_insn "lshrsi_16" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (const_int 16)))] + "!TARGET_68060" + "* +{ + CC_STATUS_INIT; + return \"clr%.w %0\;swap %0\"; +}") + +;; On the 68000, this makes faster code in a special case. + +(define_insn "lshrsi_17_24" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "const_int_operand" "n")))] + "(! TARGET_68020 && !TARGET_5200 + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24)" + "* +{ + /* I think lsr%.w sets the CC properly. */ + operands[2] = GEN_INT (INTVAL (operands[2]) - 16); + return \"clr%.w %0\;swap %0\;lsr%.w %2,%0\"; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "" + "lsr%.l %2,%0") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "register_operand" "=d") + (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "!TARGET_5200" + "lsr%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (lshiftrt:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "!TARGET_5200" + "lsr%.w %1,%0") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "!TARGET_5200" + "lsr%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (lshiftrt:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "!TARGET_5200" + "lsr%.b %1,%0") + +;; rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "dINO")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 16) + return \"swap %0\"; + else if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 16) + { + operands[2] = GEN_INT (32 - INTVAL (operands[2])); + return \"ror%.l %2,%0\"; + } + else + return \"rol%.l %2,%0\"; +}") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "register_operand" "=d") + (rotate:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "dIP")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 8) + { + operands[2] = GEN_INT (16 - INTVAL (operands[2])); + return \"ror%.w %2,%0\"; + } + else + return \"rol%.w %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (rotate:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dIP")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 8) + { + operands[2] = GEN_INT (16 - INTVAL (operands[2])); + return \"ror%.w %2,%0\"; + } + else + return \"rol%.w %2,%0\"; +}") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (rotate:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 4) + { + operands[2] = GEN_INT (8 - INTVAL (operands[2])); + return \"ror%.b %2,%0\"; + } + else + return \"rol%.b %2,%0\"; +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (rotate:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "!TARGET_5200" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 4) + { + operands[2] = GEN_INT (8 - INTVAL (operands[2])); + return \"ror%.b %2,%0\"; + } + else + return \"rol%.b %2,%0\"; +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=d") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "dI")))] + "!TARGET_5200" + "ror%.l %2,%0") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "register_operand" "=d") + (rotatert:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "general_operand" "dI")))] + "!TARGET_5200" + "ror%.w %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) + (rotatert:HI (match_dup 0) + (match_operand:HI 1 "general_operand" "dI")))] + "!TARGET_5200" + "ror%.w %1,%0") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "register_operand" "=d") + (rotatert:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "general_operand" "dI")))] + "!TARGET_5200" + "ror%.b %2,%0") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "register_operand" "+d")) + (rotatert:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "dI")))] + "!TARGET_5200" + "ror%.b %1,%0") + + +;; Bit set/clear in memory byte. + +;; set bit, bit number is int +(define_insn "bsetmemqi" + [(set (match_operand:QI 0 "memory_operand" "+m") + (ior:QI (subreg:QI (ashift:SI (const_int 1) + (match_operand:SI 1 "general_operand" "d")) 0) + (match_dup 0)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bset %1,%0\"; +}") + +;; set bit, bit number is (sign/zero)_extended from HImode/QImode +(define_insn "" + [(set (match_operand:QI 0 "memory_operand" "+m") + (ior:QI (subreg:QI (ashift:SI (const_int 1) + (match_operator:SI 2 "extend_operator" + [(match_operand 1 "general_operand" "d")])) 0) + (match_dup 0)))] + "" + "* +{ + CC_STATUS_INIT; + return \"bset %1,%0\"; +}") + +;; clear bit, bit number is int +(define_insn "bclrmemqi" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m") + (const_int 1) + (minus:SI (const_int 7) + (match_operand:SI 1 "general_operand" "d"))) + (const_int 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"bclr %1,%0\"; +}") + +;; clear bit, bit number is (sign/zero)_extended from HImode/QImode +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m") + (const_int 1) + (minus:SI (const_int 7) + (match_operator:SI 2 "extend_operator" + [(match_operand 1 "general_operand" "d")]))) + (const_int 0))] + "" + "* +{ + CC_STATUS_INIT; + return \"bclr %1,%0\"; +}") + +;; Special cases of bit-field insns which we should +;; recognize in preference to the general case. +;; These handle aligned 8-bit and 16-bit fields, +;; which can usually be done with move instructions. + +; +; Special case for 32-bit field in memory. This only occurs when 32-bit +; alignment of structure members is specified. +; +; The move is allowed to be odd byte aligned, because that's still faster +; than an odd byte aligned bit field instruction. +; +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (const_int 32) + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "general_operand" "rmi"))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[2]) % 8) == 0 + && ! mode_dependent_address_p (XEXP (operands[0], 0))" + "* +{ + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + return \"move%.l %3,%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+do") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")) + (match_operand:SI 3 "register_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16) + && INTVAL (operands[2]) % INTVAL (operands[1]) == 0 + && (GET_CODE (operands[0]) == REG + || ! mode_dependent_address_p (XEXP (operands[0], 0)))" + "* +{ + if (REG_P (operands[0])) + { + if (INTVAL (operands[1]) + INTVAL (operands[2]) != 32) + return \"bfins %3,%0{%b2:%b1}\"; + } + else + operands[0] + = adj_offsettable_operand (operands[0], INTVAL (operands[2]) / 8); + + if (GET_CODE (operands[3]) == MEM) + operands[3] = adj_offsettable_operand (operands[3], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[1]) == 8) + return \"move%.b %3,%0\"; + return \"move%.w %3,%0\"; +}") + + +; +; Special case for 32-bit field in memory. This only occurs when 32-bit +; alignment of structure members is specified. +; +; The move is allowed to be odd byte aligned, because that's still faster +; than an odd byte aligned bit field instruction. +; +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "o") + (const_int 32) + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[3]) % 8) == 0 + && ! mode_dependent_address_p (XEXP (operands[1], 0))" + "* +{ + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + return \"move%.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=&d") + (zero_extract:SI (match_operand:SI 1 "register_operand" "do") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + cc_status.flags |= CC_NOT_NEGATIVE; + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfextu %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + output_asm_insn (\"clr%.l %0\", operands); + if (GET_CODE (operands[0]) == MEM) + operands[0] = adj_offsettable_operand (operands[0], + (32 - INTVAL (operands[1])) / 8); + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\"; + return \"move%.w %1,%0\"; +}") + +; +; Special case for 32-bit field in memory. This only occurs when 32-bit +; alignment of structure members is specified. +; +; The move is allowed to be odd byte aligned, because that's still faster +; than an odd byte aligned bit field instruction. +; +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "o") + (const_int 32) + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[3]) % 8) == 0 + && ! mode_dependent_address_p (XEXP (operands[1], 0))" + "* +{ + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + return \"move%.l %1,%0\"; +}") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "register_operand" "do") + (match_operand:SI 2 "const_int_operand" "n") + (match_operand:SI 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16) + && INTVAL (operands[3]) % INTVAL (operands[2]) == 0 + && (GET_CODE (operands[1]) == REG + || ! mode_dependent_address_p (XEXP (operands[1], 0)))" + "* +{ + if (REG_P (operands[1])) + { + if (INTVAL (operands[2]) + INTVAL (operands[3]) != 32) + return \"bfexts %1{%b3:%b2},%0\"; + } + else + operands[1] + = adj_offsettable_operand (operands[1], INTVAL (operands[3]) / 8); + + if (INTVAL (operands[2]) == 8) + return \"move%.b %1,%0\;extb%.l %0\"; + return \"move%.w %1,%0\;ext%.l %0\"; +}") + +;; Bit field instructions, general cases. +;; "o,d" constraint causes a nonoffsettable memref to match the "o" +;; so that its address is reloaded. + +(define_expand "extv" + [(set (match_operand:SI 0 "general_operand" "") + (sign_extract:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "TARGET_68020 && TARGET_BITFIELD" + "") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:QI 1 "memory_operand" "o") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_expand "extzv" + [(set (match_operand:SI 0 "general_operand" "") + (zero_extract:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "TARGET_68020 && TARGET_BITFIELD" + "") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d,d") + (zero_extract:SI (match_operand:QI 1 "memory_operand" "o,d") + (match_operand:SI 2 "general_operand" "di,di") + (match_operand:SI 3 "general_operand" "di,di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) != 32) + cc_status.flags |= CC_NOT_NEGATIVE; + } + else + { + CC_STATUS_INIT; + } + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (xor:SI (zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)) + (match_operand 3 "const_int_operand" "n")))] + "TARGET_68020 && TARGET_BITFIELD + && (INTVAL (operands[3]) == -1 + || (GET_CODE (operands[1]) == CONST_INT + && (~ INTVAL (operands[3]) & ((1 << INTVAL (operands[1]))- 1)) == 0))" + "* +{ + CC_STATUS_INIT; + return \"bfchg %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")) + (match_operand:SI 3 "register_operand" ""))] + "TARGET_68020 && TARGET_BITFIELD" + "") + +(define_insn "" + [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+o") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "register_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "bfins %3,%0{%b2:%b1}") + +;; Now recognize bit field insns that operate on registers +;; (or at least were intended to do so). + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (sign_extract:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "bfexts %1{%b3:%b2},%0") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=d") + (zero_extract:SI (match_operand:SI 1 "register_operand" "d") + (match_operand:SI 2 "general_operand" "di") + (match_operand:SI 3 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) != 32) + cc_status.flags |= CC_NOT_NEGATIVE; + } + else + { + CC_STATUS_INIT; + } + return \"bfextu %1{%b3:%b2},%0\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int 0))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfclr %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (const_int -1))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + CC_STATUS_INIT; + return \"bfset %0{%b2:%b1}\"; +}") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+d") + (match_operand:SI 1 "general_operand" "di") + (match_operand:SI 2 "general_operand" "di")) + (match_operand:SI 3 "register_operand" "d"))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ +#if 0 + /* These special cases are now recognized by a specific pattern. */ + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 16 && INTVAL (operands[2]) == 16) + return \"move%.w %3,%0\"; + if (GET_CODE (operands[1]) == CONST_INT && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[1]) == 24 && INTVAL (operands[2]) == 8) + return \"move%.b %3,%0\"; +#endif + return \"bfins %3,%0{%b2:%b1}\"; +}") + +;; Special patterns for optimizing bit-field instructions. + +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + GEN_INT (width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + + +;;; now handle the register cases +(define_insn "" + [(set (cc0) + (zero_extract:SI (match_operand:SI 0 "register_operand" "d") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "general_operand" "di")))] + "TARGET_68020 && TARGET_BITFIELD" + "* +{ + if (operands[1] == const1_rtx + && GET_CODE (operands[2]) == CONST_INT) + { + int width = GET_CODE (operands[0]) == REG ? 31 : 7; + return output_btst (operands, + GEN_INT (width - INTVAL (operands[2])), + operands[0], + insn, 1000); + /* Pass 1000 as SIGNPOS argument so that btst will + not think we are testing the sign bit for an `and' + and assume that nonzero implies a negative result. */ + } + if (INTVAL (operands[1]) != 32) + cc_status.flags = CC_NOT_NEGATIVE; + return \"bftst %0{%b2:%b1}\"; +}") + +(define_insn "scc0_di" + [(set (match_operand:QI 0 "general_operand" "=dm") + (match_operator 1 "valid_dbcc_comparison_p" + [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] + "! TARGET_5200" + "* +{ + return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); +} ") + +(define_insn "scc0_di_5200" + [(set (match_operand:QI 0 "general_operand" "=d") + (match_operator 1 "valid_dbcc_comparison_p" + [(match_operand:DI 2 "general_operand" "ro") (const_int 0)]))] + "TARGET_5200" + "* +{ + return output_scc_di (operands[1], operands[2], const0_rtx, operands[0]); +} ") + +(define_insn "scc_di" + [(set (match_operand:QI 0 "general_operand" "=dm,dm") + (match_operator 1 "valid_dbcc_comparison_p" + [(match_operand:DI 2 "general_operand" "ro,r") + (match_operand:DI 3 "general_operand" "r,ro")]))] + "! TARGET_5200" + "* +{ + return output_scc_di (operands[1], operands[2], operands[3], operands[0]); +} ") + +(define_insn "scc_di_5200" + [(set (match_operand:QI 0 "general_operand" "=d,d") + (match_operator 1 "valid_dbcc_comparison_p" + [(match_operand:DI 2 "general_operand" "ro,r") + (match_operand:DI 3 "general_operand" "r,ro")]))] + "TARGET_5200" + "* +{ + return output_scc_di (operands[1], operands[2], operands[3], operands[0]); +} ") + +(define_expand "seq" + [(set (match_operand:QI 0 "general_operand" "") + (eq:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (eq:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (eq:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"seq %0\", \"fseq %0\", \"seq %0\"); +") + +(define_expand "sne" + [(set (match_operand:QI 0 "general_operand" "") + (ne:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (ne:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsne %0\", \"sne %0\"); +") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (ne:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sne %0\", \"fsne %0\", \"sne %0\"); +") + +(define_expand "sgt" + [(set (match_operand:QI 0 "general_operand" "") + (gt:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (gt:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", 0); +") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (gt:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sgt %0\", \"fsgt %0\", 0); +") + +(define_expand "sgtu" + [(set (match_operand:QI 0 "general_operand" "") + (gtu:QI (cc0) (const_int 0)))] + "" + "") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (gtu:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (gtu:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + return \"shi %0\"; ") + +(define_expand "slt" + [(set (match_operand:QI 0 "general_operand" "") + (lt:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (lt:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (lt:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"slt %0\", \"fslt %0\", \"smi %0\"); ") + +(define_expand "sltu" + [(set (match_operand:QI 0 "general_operand" "") + (ltu:QI (cc0) (const_int 0)))] + "" + "") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (ltu:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (ltu:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + return \"scs %0\"; ") + +(define_expand "sge" + [(set (match_operand:QI 0 "general_operand" "") + (ge:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (ge:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (ge:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + OUTPUT_JUMP (\"sge %0\", \"fsge %0\", \"spl %0\"); ") + +(define_expand "sgeu" + [(set (match_operand:QI 0 "general_operand" "") + (geu:QI (cc0) (const_int 0)))] + "" + "") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (geu:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (geu:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + return \"scc %0\"; ") + +(define_expand "sle" + [(set (match_operand:QI 0 "general_operand" "") + (le:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_68060 && m68k_last_compare_had_fp_operands) + { + m68k_last_compare_had_fp_operands = 0; + FAIL; + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (le:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", 0); +") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (le:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* + cc_status = cc_prev_status; + OUTPUT_JUMP (\"sle %0\", \"fsle %0\", 0); +") + +(define_expand "sleu" + [(set (match_operand:QI 0 "general_operand" "") + (leu:QI (cc0) (const_int 0)))] + "" + "") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=dm") + (leu:QI (cc0) (const_int 0)))] + "! TARGET_5200" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +(define_insn "" + [(set (match_operand:QI 0 "general_operand" "=d") + (leu:QI (cc0) (const_int 0)))] + "TARGET_5200" + "* cc_status = cc_prev_status; + return \"sls %0\"; ") + +;; Basic conditional jump instructions. + +(define_insn "beq0_di" + [(set (pc) + (if_then_else (eq (match_operand:DI 0 "general_operand" "d*ao,<>") + (const_int 0)) + (label_ref (match_operand 1 "" ",")) + (pc))) + (clobber (match_scratch:SI 2 "=d,d"))] + "" + "* +{ + CC_STATUS_INIT; + if (which_alternative == 1) +#ifdef MOTOROLA + return \"move%.l %0,%2\;or%.l %0,%2\;jbeq %l1\"; +#else + return \"move%.l %0,%2\;or%.l %0,%2\;jeq %l1\"; +#endif + if ((cc_prev_status.value1 + && rtx_equal_p (cc_prev_status.value1, operands[0])) + || (cc_prev_status.value2 + && rtx_equal_p (cc_prev_status.value2, operands[0]))) + { + cc_status = cc_prev_status; +#ifdef MOTOROLA + return \"jbeq %l1\"; +#else + return \"jeq %l1\"; +#endif + } + if (GET_CODE (operands[0]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[3] = adj_offsettable_operand (operands[0], 4); + if (! ADDRESS_REG_P (operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[3])) + { +#ifdef MOTOROLA + return \"or%.l %0,%2\;jbeq %l1\"; +#else + return \"or%.l %0,%2\;jeq %l1\"; +#endif + } + else + { +#ifdef MOTOROLA + return \"or%.l %3,%2\;jbeq %l1\"; +#else + return \"or%.l %3,%2\;jeq %l1\"; +#endif + } + } +#ifdef MOTOROLA + return \"move%.l %0,%2\;or%.l %3,%2\;jbeq %l1\"; +#else + return \"move%.l %0,%2\;or%.l %3,%2\;jeq %l1\"; +#endif + } + operands[4] = gen_label_rtx(); + if (TARGET_68020 || TARGET_5200) + { +#ifdef MOTOROLA + output_asm_insn (\"tst%.l %0\;jbne %l4\;tst%.l %3\;jbeq %l1\", operands); +#else + output_asm_insn (\"tst%.l %0\;jne %l4\;tst%.l %3\;jeq %l1\", operands); +#endif + } + else + { +#ifdef MOTOROLA +#ifdef SGS_CMP_ORDER + output_asm_insn (\"cmp%.w %0,%#0\;jbne %l4\;cmp%.w %3,%#0\;jbeq %l1\", operands); +#else + output_asm_insn (\"cmp%.w %#0,%0\;jbne %l4\;cmp%.w %#0,%3\;jbeq %l1\", operands); +#endif +#else + output_asm_insn (\"cmp%.w %#0,%0\;jne %l4\;cmp%.w %#0,%3\;jeq %l1\", operands); +#endif + } + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[4])); + return \"\"; +} ") + +(define_insn "bne0_di" + [(set (pc) + (if_then_else (ne (match_operand:DI 0 "general_operand" "do,*a") + (const_int 0)) + (label_ref (match_operand 1 "" ",")) + (pc))) + (clobber (match_scratch:SI 2 "=d,X"))] + "" + "* +{ + if ((cc_prev_status.value1 + && rtx_equal_p (cc_prev_status.value1, operands[0])) + || (cc_prev_status.value2 + && rtx_equal_p (cc_prev_status.value2, operands[0]))) + { + cc_status = cc_prev_status; +#ifdef MOTOROLA + return \"jbne %l1\"; +#else + return \"jne %l1\"; +#endif + } + CC_STATUS_INIT; + if (GET_CODE (operands[0]) == REG) + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + else + operands[3] = adj_offsettable_operand (operands[0], 4); + if (!ADDRESS_REG_P (operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[0])) + { + if (reg_overlap_mentioned_p (operands[2], operands[3])) + { +#ifdef MOTOROLA + return \"or%.l %0,%2\;jbne %l1\"; +#else + return \"or%.l %0,%2\;jne %l1\"; +#endif + } + else + { +#ifdef MOTOROLA + return \"or%.l %3,%2\;jbne %l1\"; +#else + return \"or%.l %3,%2\;jne %l1\"; +#endif + } + } +#ifdef MOTOROLA + return \"move%.l %0,%2\;or%.l %3,%2\;jbne %l1\"; +#else + return \"move%.l %0,%2\;or%.l %3,%2\;jne %l1\"; +#endif + } + if (TARGET_68020 || TARGET_5200) + { +#ifdef MOTOROLA + return \"tst%.l %0\;jbne %l1\;tst%.l %3\;jbne %l1\"; +#else + return \"tst%.l %0\;jne %l1\;tst%.l %3\;jne %l1\"; +#endif + } + else + { +#ifdef MOTOROLA +#ifdef SGS_CMP_ORDER + return \"cmp%.w %0,%#0\;jbne %l1\;cmp%.w %3,%#0\;jbne %l1\"; +#else + return \"cmp%.w %#0,%0\;jbne %l1\;cmp%.w %#0,%3\;jbne %l1\"; +#endif +#else + return \"cmp%.w %#0,%0\;jne %l1\;cmp%.w %#0,%3\;jne %l1\"; +#endif + } +} ") + +(define_insn "bge0_di" + [(set (pc) + (if_then_else (ge (match_operand:DI 0 "general_operand" "ro") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + if ((cc_prev_status.value1 + && rtx_equal_p (cc_prev_status.value1, operands[0])) + || (cc_prev_status.value2 + && rtx_equal_p (cc_prev_status.value2, operands[0]))) + { + cc_status = cc_prev_status; + if (cc_status.flags & CC_REVERSED) + { +#ifdef MOTOROLA + return \"jble %l1\"; +#else + return \"jle %l1\"; +#endif + } + else + { +#ifdef MOTOROLA + return \"jbpl %l1\"; +#else + return \"jpl %l1\"; +#endif + } + } + CC_STATUS_INIT; + if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (operands[0])) + output_asm_insn(\"tst%.l %0\", operands); + else + { + /* On an address reg, cmpw may replace cmpl. */ +#ifdef SGS_CMP_ORDER + output_asm_insn(\"cmp%.w %0,%#0\", operands); +#else + output_asm_insn(\"cmp%.w %#0,%0\", operands); +#endif + } + +#ifdef MOTOROLA + return \"jbpl %l1\"; +#else + return \"jpl %l1\"; +#endif +} ") + +(define_insn "blt0_di" + [(set (pc) + (if_then_else (lt (match_operand:DI 0 "general_operand" "ro") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + if ((cc_prev_status.value1 + && rtx_equal_p (cc_prev_status.value1, operands[0])) + || (cc_prev_status.value2 + && rtx_equal_p (cc_prev_status.value2, operands[0]))) + { + cc_status = cc_prev_status; + if (cc_status.flags & CC_REVERSED) + { +#ifdef MOTOROLA + return \"jbgt %l1\"; +#else + return \"jgt %l1\"; +#endif + } + else + { +#ifdef MOTOROLA + return \"jbmi %l1\"; +#else + return \"jmi %l1\"; +#endif + } + } + CC_STATUS_INIT; + if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (operands[0])) + output_asm_insn(\"tst%.l %0\", operands); + else + { + /* On an address reg, cmpw may replace cmpl. */ +#ifdef SGS_CMP_ORDER + output_asm_insn(\"cmp%.w %0,%#0\", operands); +#else + output_asm_insn(\"cmp%.w %#0,%0\", operands); +#endif + } + +#ifdef MOTOROLA + return \"jbmi %l1\"; +#else + return \"jmi %l1\"; +#endif +} ") + +(define_insn "beq" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "bne" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "bgt" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbgt %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjgt %l0\", 0); +#endif +") + +(define_insn "bgtu" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +(define_insn "blt" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fblt %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjlt %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "bltu" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "bge" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbge %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjge %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "bgeu" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "ble" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fble %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjle %l0\", 0); +#endif +") + +(define_insn "bleu" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +;; Negated conditional jump instructions. + +(define_insn "" + [(set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbne %l0\", \"fbne %l0\", \"jbne %l0\"); +#else + OUTPUT_JUMP (\"jne %l0\", \"fjne %l0\", \"jne %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbeq %l0\", \"fbeq %l0\", \"jbeq %l0\"); +#else + OUTPUT_JUMP (\"jeq %l0\", \"fjeq %l0\", \"jeq %l0\"); +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jble %l0\", \"fbngt %l0\", 0); +#else + OUTPUT_JUMP (\"jle %l0\", \"fjngt %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbls %l0\"; +#else + return \"jls %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbge %l0\", \"fbnlt %l0\", \"jbpl %l0\"); +#else + OUTPUT_JUMP (\"jge %l0\", \"fjnlt %l0\", \"jpl %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcc %l0\"; +#else + return \"jcc %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jblt %l0\", \"fbnge %l0\", \"jbmi %l0\"); +#else + OUTPUT_JUMP (\"jlt %l0\", \"fjnge %l0\", \"jmi %l0\"); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbcs %l0\"; +#else + return \"jcs %l0\"; +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + OUTPUT_JUMP (\"jbgt %l0\", \"fbnle %l0\", 0); +#else + OUTPUT_JUMP (\"jgt %l0\", \"fjnle %l0\", 0); +#endif +") + +(define_insn "" + [(set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +#ifdef MOTOROLA + return \"jbhi %l0\"; +#else + return \"jhi %l0\"; +#endif +") + +;; Unconditional and other jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "* +#ifdef MOTOROLA + return \"jbra %l0\"; +#else + return \"jra %l0\"; +#endif +") + +;; We support two different ways of handling dispatch tables. +;; The NeXT uses absolute tables, and other machines use relative. +;; This define_expand can generate either kind. +(define_expand "tablejump" + [(parallel [(set (pc) (match_operand 0 "" "")) + (use (label_ref (match_operand 1 "" "")))])] + "" + " +{ +#ifdef CASE_VECTOR_PC_RELATIVE + operands[0] = gen_rtx_PLUS (SImode, pc_rtx, + gen_rtx_SIGN_EXTEND (SImode, operands[0])); +#endif +}") + +;; Jump to variable address from dispatch table of absolute addresses. +(define_insn "" + [(set (pc) (match_operand:SI 0 "register_operand" "a")) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +#ifdef MOTOROLA + return \"jmp (%0)\"; +#else + return \"jmp %0@\"; +#endif +") + +;; Jump to variable address from dispatch table of relative addresses. +(define_insn "" + [(set (pc) + (plus:SI (pc) + (sign_extend:SI (match_operand:HI 0 "register_operand" "r")))) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +#ifdef ASM_RETURN_CASE_JUMP + ASM_RETURN_CASE_JUMP; +#else +#ifdef SGS +#ifdef ASM_OUTPUT_CASE_LABEL + if (TARGET_5200) + return \"ext%.l %0\;jmp 6(%%pc,%0.l)\"; + else + return \"jmp 6(%%pc,%0.w)\"; +#else + if (TARGET_5200) + { +#ifdef CRDS + return \"ext%.l %0\;jmp 2(pc,%0.l)\"; +#else + return \"extl %0\;jmp 2(%%pc,%0.l)\"; +#endif /* end !CRDS */ + } + else + { +#ifdef CRDS + return \"jmp 2(pc,%0.w)\"; +#else + return \"jmp 2(%%pc,%0.w)\"; +#endif /* end !CRDS */ + } +#endif +#else /* not SGS */ + if (TARGET_5200) + { +#ifdef MOTOROLA + return \"ext%.l %0\;jmp (2,pc,%0.l)\"; +#else + return \"extl %0\;jmp pc@(2,%0:l)\"; +#endif + } + else + { +#ifdef MOTOROLA + return \"jmp (2,pc,%0.w)\"; +#else + return \"jmp pc@(2,%0:w)\"; +#endif + } +#endif +#endif +") + +;; Decrement-and-branch insns. +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:HI 0 "general_operand" "+d*g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + { +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;jbcc %l1\"; +#else + return \"subq%.w %#1,%0\;jbcc %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;jcc %l1\"; +#endif + } +#ifdef MOTOROLA +#ifdef SGS_CMP_ORDER +#ifdef NO_ADDSUB_Q + return \"sub%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#else + return \"subq%.w %#1,%0\;cmp%.w %0,%#-1\;jbne %l1\"; +#endif +#else /* not SGS_CMP_ORDER */ + return \"subq%.w %#1,%0\;cmp%.w %#-1,%0\;jbne %l1\"; +#endif +#else /* not MOTOROLA */ + return \"subqw %#1,%0\;cmpw %#-1,%0\;jne %l1\"; +#endif +}") + +(define_insn "" + [(set (pc) + (if_then_else + (ne (match_operand:SI 0 "general_operand" "+d*g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_5200" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;sub%.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub%.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jbcc %l1\"; +#endif /* NO_ADDSUB_Q */ +#ifdef SGS_CMP_ORDER +#ifdef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else /* not SGS_CMP_ORDER */ + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif /* not SGS_CMP_ORDER */ +#else /* not MOTOROLA */ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif /* not MOTOROLA */ +}") + +;; Two dbra patterns that use REG_NOTES info generated by strength_reduce. + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:HI (match_operand:HI 0 "general_operand" "+d*am") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))] + "!TARGET_5200 && find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub%.w %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.w %#1,%0\;jbcc %l1\"; +#endif +#ifdef SGS_CMP_ORDER +#ifdef NO_ADDSUB_Q + return \"sub.w %#1,%0\;cmp.w %0,%#-1\;jbne %l1\"; +#else + return \"subq.w %#1,%0\;cmp.w %0,%#-1\;jbne %l1\"; +#endif +#else /* not SGS_CMP_ORDER */ + return \"subq.w %#1,%0\;cmp.w %#-1,%0\;jbne %l1\"; +#endif /* not SGS_CMP_ORDER */ +#else /* not MOTOROLA */ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subqw %#1,%0\;jcc %l1\"; + return \"subqw %#1,%0\;cmpw %#-1,%0\;jne %l1\"; +#endif /* not MOTOROLA */ +}") + +(define_expand "decrement_and_branch_until_zero" + [(parallel [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))])] + "" + "") + +(define_insn "" + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "general_operand" "+d*am") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "!TARGET_5200 && find_reg_note (insn, REG_NONNEG, 0)" + "* +{ + CC_STATUS_INIT; +#ifdef MOTOROLA +#ifdef NO_ADDSUB_Q + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;sub%.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"sub%.l %#1,%0\;jbcc %l1\"; +#else + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subq%.l %#1,%0\;jbcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subq%.l %#1,%0\;jbcc %l1\"; +#endif +#ifdef SGS_CMP_ORDER +#ifdef NO_ADDSUB_Q + return \"sub.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#else + return \"subq.l %#1,%0\;cmp.l %0,%#-1\;jbne %l1\"; +#endif +#else /* not SGS_CMP_ORDER */ + return \"subq.l %#1,%0\;cmp.l %#-1,%0\;jbne %l1\"; +#endif /* not SGS_CMP_ORDER */ +#else /* not MOTOROLA */ + if (DATA_REG_P (operands[0])) + return \"dbra %0,%l1\;clr%.w %0\;subql %#1,%0\;jcc %l1\"; + if (GET_CODE (operands[0]) == MEM) + return \"subql %#1,%0\;jcc %l1\"; + return \"subql %#1,%0\;cmpl %#-1,%0\;jne %l1\"; +#endif /* not MOTOROLA */ +}") + + +;; For PIC calls, in order to be able to support +;; dynamic linker LAZY BINDING, all the procedure calls need to go +;; through the PLT (Procedure Linkage Table) section in PIC mode. +;; +;; PIC calls are handled by loading the address of the function into a +;; register (via movsi), then emitting a register indirect call using +;; the "jsr" function call syntax. +;; +;; When outputting MIT syntax (e.g. on Suns), we add a bogus extra +;; operand to the jbsr statement to indicate that this call should +;; go through the PLT (why? because this is the way that Sun does it). +;; +;; We have different patterns for PIC calls and non-PIC calls. The +;; different patterns are only used to choose the right syntax. +;; +;; The svr4 m68k assembler recognizes this syntax: `bsr FUNC@PLTPC' and it +;; will create the correct relocation entry (R_68K_PLT32) for `FUNC', +;; that tells the linker editor to create an entry for `FUNC' in PLT +;; section at link time. However, all global objects reference are still +;; done by using `OBJ@GOT'. So, the goal here is to output the function +;; call operand as `FUNC@PLTPC', but output object operand as `OBJ@GOT'. +;; We need to have a way to differentiate these two different operands. +;; +;; The strategy I use here is to use SYMBOL_REF_FLAG to differentiate +;; these two different operands. The macro LEGITIMATE_PIC_OPERAND_P needs +;; to be changed to recognize function calls symbol_ref operand as a valid +;; PIC operand (by checking whether SYMBOL_REF_FLAG is set). This will +;; avoid the compiler to load this symbol_ref operand into a register. +;; Remember, the operand "foo@PLTPC" cannot be called via jsr directly +;; since the value is a PC relative offset, not a real address. +;; +;; All global objects are treated in the similar way as in SUN3. The only +;; difference is: on m68k svr4, the reference of such global object needs +;; to end with a suffix "@GOT" so the assembler and linker know to create +;; an entry for it in GOT (Global Offset Table) section. This is done in +;; m68k.c. + +;; Call subroutine with no return value. +(define_expand "call" + [(call (match_operand:QI 0 "memory_operand" "") + (match_operand:SI 1 "general_operand" ""))] + ;; Operand 1 not really used on the m68000. + + "" + " +{ + if (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) + SYMBOL_REF_FLAG (XEXP (operands[0], 0)) = 1; +}") + +;; This is a normal call sequence. +(define_insn "" + [(call (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + + "! flag_pic" + "* +#if defined (MOTOROLA) && !defined (USE_GAS) +#ifdef MOTOROLA_BSR + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) + return \"bsr %0\"; +#endif + return \"jsr %0\"; +#else + return \"jbsr %0\"; +#endif +") + +;; This is a PIC call sequence. +(define_insn "" + [(call (match_operand:QI 0 "memory_operand" "o") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not really used on the m68000. + + "flag_pic" + "* + if (GET_CODE (operands[0]) == MEM + && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) +#ifdef MOTOROLA +#ifdef HPUX_ASM + return \"bsr.l %0\"; +#else +#ifdef USE_GAS + return \"bsr.l %0@PLTPC\"; +#else + return \"bsr %0@PLTPC\"; +#endif +#endif +#else + /* The ',a1' is a dummy argument telling the Sun assembler we want PIC, + GAS just plain ignores it. */ + return \"jbsr %0,a1\"; +#endif + return \"jsr %0\"; +") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). +;; See comments before "call" regarding PIC calls. +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "memory_operand" "") + (match_operand:SI 2 "general_operand" "")))] + ;; Operand 2 not really used on the m68000. + "" + " +{ + if (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + SYMBOL_REF_FLAG (XEXP (operands[1], 0)) = 1; +}") + +;; This is a normal call_value +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "memory_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "! flag_pic" + "* +#if defined (MOTOROLA) && !defined (USE_GAS) +#ifdef MOTOROLA_BSR + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + return \"bsr %1\"; +#endif + return \"jsr %1\"; +#else + return \"jbsr %1\"; +#endif +") + +;; This is a PIC call_value +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "memory_operand" "o") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not really used on the m68000. + "flag_pic" + "* + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + { +#ifdef MOTOROLA +#ifdef HPUX_ASM + return \"bsr.l %1\"; +#else +#ifdef USE_GAS + return \"bsr.l %1@PLTPC\"; +#else + return \"bsr %1@PLTPC\"; +#endif +#endif +#else + /* The ',a1' is a dummy argument telling the Sun assembler we want PIC + GAS just plain ignores it. */ + return \"jbsr %1,a1\"; +#endif + } + return \"jsr %1\"; +") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "NEEDS_UNTYPED_CALL" + " +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] + "" + "") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_insn "probe" + [(reg:SI 15)] + "NEED_PROBE" + "* +{ + operands[0] = gen_rtx_PLUS (SImode, stack_pointer_rtx, + GEN_INT (NEED_PROBE)); + return \"tstl %a0\"; +}") + +;; Used for frameless functions which save no regs and allocate no locals. +(define_insn "return" + [(return)] + "USE_RETURN_INSN" + "* +{ + if (current_function_pops_args == 0) + return \"rts\"; + operands[0] = GEN_INT (current_function_pops_args); + return \"rtd %0\"; +}") + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "address_operand" "p"))] + "" + "jmp %a0") + +;; This should not be used unless the add/sub insns can't be. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=a") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ +#ifndef SGS_NO_LI + /* Recognize an insn that refers to a table of offsets. Such an insn will + need to refer to a label on the insn. So output one. Use the + label-number of the table of offsets to generate this label. This code, + and similar code above, assumes that there will be at most one reference + to each table. */ + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == LABEL_REF + && GET_CODE (XEXP (operands[1], 0)) != PLUS) + { + rtx labelref = XEXP (operands[1], 1); +#if defined (MOTOROLA) && !defined (SGS_SWITCH_TABLES) +#ifdef SGS + asm_fprintf (asm_out_file, \"\\tset %LLI%d,.+2\\n\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#else /* not SGS */ + asm_fprintf (asm_out_file, \"\\t.set %LLI%d,.+2\\n\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#endif /* not SGS */ +#else /* SGS_SWITCH_TABLES or not MOTOROLA */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LI\", + CODE_LABEL_NUMBER (XEXP (labelref, 0))); +#ifdef SGS_SWITCH_TABLES + /* Set flag saying we need to define the symbol + LD%n (with value L%n-LI%n) at the end of the switch table. */ + switch_table_difference_label_flag = 1; +#endif /* SGS_SWITCH_TABLES */ +#endif /* SGS_SWITCH_TABLES or not MOTOROLA */ + } +#endif /* SGS_NO_LI */ + + return \"lea %a1,%0\"; +}") + +;; This is the first machine-dependent peephole optimization. +;; It is useful when a floating value is returned from a function call +;; and then is moved into an FP register. +;; But it is mainly intended to test the support for these optimizations. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4))) + (set (match_operand:DF 0 "register_operand" "=f") + (match_operand:DF 1 "register_operand" "ad"))] + "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" + "* +{ + rtx xoperands[2]; + xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + output_asm_insn (\"move%.l %1,%@\", xoperands); + output_asm_insn (\"move%.l %1,%-\", operands); + return \"fmove%.d %+,%0\"; +} +") + +;; Optimize a stack-adjust followed by a push of an argument. +;; This is said to happen frequently with -msoft-float +;; when there are consecutive library calls. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) + (match_operand:SI 0 "const_int_operand" "n"))) + (set (match_operand:SF 1 "push_operand" "=m") + (match_operand:SF 2 "general_operand" "rmfF"))] + "INTVAL (operands[0]) >= 4 + && ! reg_mentioned_p (stack_pointer_rtx, operands[2])" + "* +{ + if (INTVAL (operands[0]) > 4) + { + rtx xoperands[2]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = GEN_INT (INTVAL (operands[0]) - 4); +#ifndef NO_ADDSUB_Q + if (INTVAL (xoperands[1]) <= 8) + { + if (!TARGET_5200) + output_asm_insn (\"addq%.w %1,%0\", xoperands); + else + output_asm_insn (\"addq%.l %1,%0\", xoperands); + } + else if (TARGET_CPU32 && INTVAL (xoperands[1]) <= 16) + { + xoperands[1] = GEN_INT (INTVAL (xoperands[1]) - 8); + output_asm_insn (\"addq%.w %#8,%0\;addq%.w %1,%0\", xoperands); + } + else +#endif + if (INTVAL (xoperands[1]) <= 0x7FFF) + { + if (TARGET_68040) + output_asm_insn (\"add%.w %1,%0\", xoperands); + else +#ifdef MOTOROLA + output_asm_insn (\"lea (%c1,%0),%0\", xoperands); +#else + output_asm_insn (\"lea %0@(%c1),%0\", xoperands); +#endif + } + else + output_asm_insn (\"add%.l %1,%0\", xoperands); + } + if (FP_REG_P (operands[2])) + return \"fmove%.s %2,%@\"; + return \"move%.l %2,%@\"; +}") + +;; Speed up stack adjust followed by a fullword fixedpoint push. + +(define_peephole + [(set (reg:SI 15) (plus:SI (reg:SI 15) + (match_operand:SI 0 "const_int_operand" "n"))) + (set (match_operand:SI 1 "push_operand" "=m") + (match_operand:SI 2 "general_operand" "g"))] + "INTVAL (operands[0]) >= 4 + && ! reg_mentioned_p (stack_pointer_rtx, operands[2])" + "* +{ + if (INTVAL (operands[0]) > 4) + { + rtx xoperands[2]; + xoperands[0] = stack_pointer_rtx; + xoperands[1] = GEN_INT (INTVAL (operands[0]) - 4); +#ifndef NO_ADDSUB_Q + if (INTVAL (xoperands[1]) <= 8) + { + if (!TARGET_5200) + output_asm_insn (\"addq%.w %1,%0\", xoperands); + else + output_asm_insn (\"addq%.l %1,%0\", xoperands); + } + else if (TARGET_CPU32 && INTVAL (xoperands[1]) <= 16) + { + xoperands[1] = GEN_INT (INTVAL (xoperands[1]) - 8); + output_asm_insn (\"addq%.w %#8,%0\;addq%.w %1,%0\", xoperands); + } + else +#endif + if (INTVAL (xoperands[1]) <= 0x7FFF) + { + if (TARGET_68040) + output_asm_insn (\"add%.w %1,%0\", xoperands); + else + { +#ifdef MOTOROLA + output_asm_insn (\"lea (%c1,%0),%0\", xoperands); +#else + output_asm_insn (\"lea %0@(%c1),%0\", xoperands); +#endif + } + } + else + output_asm_insn (\"add%.l %1,%0\", xoperands); + } + if (operands[2] == const0_rtx) + return \"clr%.l %@\"; + return \"move%.l %2,%@\"; +}") + +;; Speed up pushing a single byte but leaving four bytes of space. + +(define_peephole + [(set (mem:QI (pre_dec:SI (reg:SI 15))) + (match_operand:QI 1 "general_operand" "dami")) + (set (reg:SI 15) (minus:SI (reg:SI 15) (const_int 2)))] + "! reg_mentioned_p (stack_pointer_rtx, operands[1])" + "* +{ + rtx xoperands[4]; + + if (GET_CODE (operands[1]) == REG) + return \"move%.l %1,%-\"; + + xoperands[1] = operands[1]; + xoperands[2] + = gen_rtx_MEM (QImode, + gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, + GEN_INT (3))); + xoperands[3] = stack_pointer_rtx; + if (!TARGET_5200) + output_asm_insn (\"subq%.w %#4,%3\;move%.b %1,%2\", xoperands); + else + output_asm_insn (\"subq%.l %#4,%3\;move%.b %1,%2\", xoperands); + return \"\"; +}") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=d") + (const_int 0)) + (set (strict_low_part (subreg:HI (match_dup 0) 0)) + (match_operand:HI 1 "general_operand" "rmn"))] + "strict_low_part_peephole_ok (HImode, prev_nonnote_insn (insn), operands[0])" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT) + { + if (operands[1] == const0_rtx + && (DATA_REG_P (operands[0]) + || GET_CODE (operands[0]) == MEM) + /* clr insns on 68000 read before writing. + This isn't so on the 68010, but we have no TARGET_68010. */ + && ((TARGET_68020 || TARGET_5200) + || !(GET_CODE (operands[0]) == MEM + && MEM_VOLATILE_P (operands[0])))) + return \"clr%.w %0\"; + } + return \"move%.w %1,%0\"; +}") + +;; dbCC peepholes +;; +;; Turns +;; loop: +;; [ ... ] +;; jCC label ; abnormal loop termination +;; dbra dN, loop ; normal loop termination +;; +;; Into +;; loop: +;; [ ... ] +;; dbCC dN, loop +;; jCC label +;; +;; Which moves the jCC condition outside the inner loop for free. +;; +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" + [(cc0) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ge (plus:HI (match_operand:HI 0 "register_operand" "+d") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:HI (match_dup 0) + (const_int -1)))])] + "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" + "* +{ + CC_STATUS_INIT; + output_dbcc_and_branch (operands); + return \"\"; +}") + +(define_peephole + [(set (pc) (if_then_else (match_operator 3 "valid_dbcc_comparison_p" + [(cc0) (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (parallel + [(set (pc) + (if_then_else + (ge (plus:SI (match_operand:SI 0 "register_operand" "+d") + (const_int -1)) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))])] + "!TARGET_5200 && DATA_REG_P (operands[0]) && ! flags_in_68881 ()" + "* +{ + CC_STATUS_INIT; + output_dbcc_and_branch (operands); + return \"\"; +}") + + +;; FPA multiply and add. +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (plus:DF (mult:DF (match_operand:DF 1 "general_operand" "%x,dmF,y") + (match_operand:DF 2 "general_operand" "xH,y,y")) + (match_operand:DF 3 "general_operand" "xH,y,dmF")))] + "TARGET_FPA" + "@ + fpma%.d %1,%w2,%w3,%0 + fpma%.d %x1,%x2,%x3,%0 + fpma%.d %x1,%x2,%x3,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (plus:SF (mult:SF (match_operand:SF 1 "general_operand" "%x,ydmF,y") + (match_operand:SF 2 "general_operand" "xH,y,ydmF")) + (match_operand:SF 3 "general_operand" "xH,ydmF,ydmF")))] + "TARGET_FPA" + "@ + fpma%.s %1,%w2,%w3,%0 + fpma%.s %1,%2,%3,%0 + fpma%.s %1,%2,%3,%0") + +;; FPA Multiply and subtract +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (mult:DF (match_operand:DF 2 "general_operand" "%xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "@ + fpms%.d %3,%w2,%w1,%0 + fpms%.d %x3,%2,%x1,%0 + fpms%.d %x3,%2,%x1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (mult:SF (match_operand:SF 2 "general_operand" "%xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "@ + fpms%.s %3,%w2,%w1,%0 + fpms%.s %3,%2,%1,%0 + fpms%.s %3,%2,%1,%0") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (minus:DF (mult:DF (match_operand:DF 1 "general_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "@ + fpmr%.d %2,%w1,%w3,%0 + fpmr%.d %x2,%1,%x3,%0 + fpmr%.d %x2,%1,%x3,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (minus:SF (mult:SF (match_operand:SF 1 "general_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "@ + fpmr%.s %2,%w1,%w3,%0 + fpmr%.s %x2,%1,%x3,%0 + fpmr%.s %x2,%1,%x3,%0") + +;; FPA Add and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (plus:DF (match_operand:DF 1 "general_operand" "%xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "@ + fpam%.d %2,%w1,%w3,%0 + fpam%.d %x2,%1,%x3,%0 + fpam%.d %x2,%1,%x3,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (plus:SF (match_operand:SF 1 "general_operand" "%xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "@ + fpam%.s %2,%w1,%w3,%0 + fpam%.s %x2,%1,%x3,%0 + fpam%.s %x2,%1,%x3,%0") + +;;FPA Subtract and multiply +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (minus:DF (match_operand:DF 1 "general_operand" "xH,y,y") + (match_operand:DF 2 "general_operand" "x,y,rmF")) + (match_operand:DF 3 "general_operand" "xH,rmF,y")))] + "TARGET_FPA" + "@ + fpsm%.d %2,%w1,%w3,%0 + fpsm%.d %x2,%1,%x3,%0 + fpsm%.d %x2,%1,%x3,%0") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=x,y,y") + (mult:DF (match_operand:DF 1 "general_operand" "xH,rmF,y") + (minus:DF (match_operand:DF 2 "general_operand" "xH,y,y") + (match_operand:DF 3 "general_operand" "x,y,rmF"))))] + "TARGET_FPA" + "@ + fpsm%.d %3,%w2,%w1,%0 + fpsm%.d %x3,%2,%x1,%0 + fpsm%.d %x3,%2,%x1,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (minus:SF (match_operand:SF 1 "general_operand" "xH,rmF,y") + (match_operand:SF 2 "general_operand" "x,y,yrmF")) + (match_operand:SF 3 "general_operand" "xH,rmF,yrmF")))] + "TARGET_FPA" + "@ + fpsm%.s %2,%w1,%w3,%0 + fpsm%.s %x2,%1,%x3,%0 + fpsm%.s %x2,%1,%x3,%0") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=x,y,y") + (mult:SF (match_operand:SF 1 "general_operand" "xH,rmF,yrmF") + (minus:SF (match_operand:SF 2 "general_operand" "xH,rmF,y") + (match_operand:SF 3 "general_operand" "x,y,yrmF"))))] + "TARGET_FPA" + "@ + fpsm%.s %3,%w2,%w1,%0 + fpsm%.s %x3,%2,%x1,%0 + fpsm%.s %x3,%2,%x1,%0") + +(define_expand "tstxf" + [(set (cc0) + (match_operand:XF 0 "nonimmediate_operand" ""))] + "TARGET_68881" + "m68k_last_compare_had_fp_operands = 1;") + +(define_insn "" + [(set (cc0) + (match_operand:XF 0 "nonimmediate_operand" "fm"))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; + return \"ftst%.x %0\"; +}") + +(define_expand "cmpxf" + [(set (cc0) + (compare (match_operand:XF 0 "nonimmediate_operand" "") + (match_operand:XF 1 "nonimmediate_operand" "")))] + "TARGET_68881" + "m68k_last_compare_had_fp_operands = 1;") + +(define_insn "" + [(set (cc0) + (compare (match_operand:XF 0 "nonimmediate_operand" "f,m") + (match_operand:XF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_68881" + "* +{ + cc_status.flags = CC_IN_68881; +#ifdef SGS_CMP_ORDER + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %0,%1\"; + else + return \"fcmp%.x %0,%f1\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.x %1,%f0\"; +#else + if (REG_P (operands[0])) + { + if (REG_P (operands[1])) + return \"fcmp%.x %1,%0\"; + else + return \"fcmp%.x %f1,%0\"; + } + cc_status.flags |= CC_REVERSED; + return \"fcmp%.x %f0,%1\"; +#endif +}") + +(define_insn "extendsfxf2" + [(set (match_operand:XF 0 "general_operand" "=fm,f") + (float_extend:XF (match_operand:SF 1 "general_operand" "f,m")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + /* Extending float to double in an fp-reg is a no-op. + NOTICE_UPDATE_CC has already assumed that the + cc will be set. So cancel what it did. */ + cc_status = cc_prev_status; + return \"\"; + } + return \"f%$move%.x %1,%0\"; + } + if (FP_REG_P (operands[0])) + return \"f%$move%.s %f1,%0\"; + return \"fmove%.x %f1,%0\"; +}") + + +(define_insn "extenddfxf2" + [(set (match_operand:XF 0 "general_operand" "=fm,f") + (float_extend:XF + (match_operand:DF 1 "general_operand" "f,m")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[0]) && FP_REG_P (operands[1])) + { + if (REGNO (operands[0]) == REGNO (operands[1])) + { + /* Extending float to double in an fp-reg is a no-op. + NOTICE_UPDATE_CC has already assumed that the + cc will be set. So cancel what it did. */ + cc_status = cc_prev_status; + return \"\"; + } + return \"fmove%.x %1,%0\"; + } + if (FP_REG_P (operands[0])) + return \"f%&move%.d %f1,%0\"; + return \"fmove%.x %f1,%0\"; +}") + +(define_insn "truncxfdf2" + [(set (match_operand:DF 0 "general_operand" "=m,!r") + (float_truncate:DF + (match_operand:XF 1 "general_operand" "f,f")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[0])) + { + output_asm_insn (\"fmove%.d %f1,%-\;move%.l %+,%0\", operands); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return \"move%.l %+,%0\"; + } + return \"fmove%.d %f1,%0\"; +}") + +(define_insn "truncxfsf2" + [(set (match_operand:SF 0 "general_operand" "=dm") + (float_truncate:SF + (match_operand:XF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.s %f1,%0") + +(define_insn "floatsixf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (float:XF (match_operand:SI 1 "general_operand" "dmi")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "floathixf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (float:XF (match_operand:HI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "floatqixf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (float:XF (match_operand:QI 1 "general_operand" "dmn")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "ftruncxf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (fix:XF (match_operand:XF 1 "general_operand" "fFm")))] + "TARGET_68881" + "* +{ + if (FP_REG_P (operands[1])) + return \"fintrz%.x %f1,%0\"; + return \"fintrz%.x %f1,%0\"; +}") + +(define_insn "fixxfqi2" + [(set (match_operand:QI 0 "general_operand" "=dm") + (fix:QI (match_operand:XF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.b %1,%0") + +(define_insn "fixxfhi2" + [(set (match_operand:HI 0 "general_operand" "=dm") + (fix:HI (match_operand:XF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.w %1,%0") + +(define_insn "fixxfsi2" + [(set (match_operand:SI 0 "general_operand" "=dm") + (fix:SI (match_operand:XF 1 "general_operand" "f")))] + "TARGET_68881" + "fmove%.l %1,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (plus:XF (float:XF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:XF 1 "nonimmediate_operand" "0")))] + "TARGET_68881" + "fadd%.l %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (plus:XF (float:XF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:XF 1 "nonimmediate_operand" "0")))] + "TARGET_68881" + "fadd%.w %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (plus:XF (float:XF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:XF 1 "general_operand" "0")))] + "TARGET_68881" + "fadd%.b %2,%0") + +(define_insn "addxf3" + [(set (match_operand:XF 0 "general_operand" "=f") + (plus:XF (match_operand:XF 1 "nonimmediate_operand" "%0") + (match_operand:XF 2 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fadd%.x %2,%0\"; + return \"fadd%.x %f2,%0\"; +}") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (minus:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "fsub%.l %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (minus:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "fsub%.w %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (minus:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "fsub%.b %2,%0") + +(define_insn "subxf3" + [(set (match_operand:XF 0 "general_operand" "=f") + (minus:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (match_operand:XF 2 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fsub%.x %2,%0\"; + return \"fsub%.x %f2,%0\"; +}") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (mult:XF (float:XF (match_operand:SI 2 "general_operand" "dmi")) + (match_operand:XF 1 "nonimmediate_operand" "0")))] + "TARGET_68881" + "fmul%.l %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (mult:XF (float:XF (match_operand:HI 2 "general_operand" "dmn")) + (match_operand:XF 1 "nonimmediate_operand" "0")))] + "TARGET_68881" + "fmul%.w %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (mult:XF (float:XF (match_operand:QI 2 "general_operand" "dmn")) + (match_operand:XF 1 "nonimmediate_operand" "0")))] + "TARGET_68881" + "fmul%.b %2,%0") + +(define_insn "mulxf3" + [(set (match_operand:XF 0 "general_operand" "=f") + (mult:XF (match_operand:XF 1 "nonimmediate_operand" "%0") + (match_operand:XF 2 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fmul%.x %2,%0\"; + return \"fmul%.x %f2,%0\"; +}") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (div:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:SI 2 "general_operand" "dmi"))))] + "TARGET_68881" + "fdiv%.l %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (div:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:HI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "fdiv%.w %2,%0") + +(define_insn "" + [(set (match_operand:XF 0 "general_operand" "=f") + (div:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (float:XF (match_operand:QI 2 "general_operand" "dmn"))))] + "TARGET_68881" + "fdiv%.b %2,%0") + +(define_insn "divxf3" + [(set (match_operand:XF 0 "general_operand" "=f") + (div:XF (match_operand:XF 1 "nonimmediate_operand" "0") + (match_operand:XF 2 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[2])) + return \"fdiv%.x %2,%0\"; + return \"fdiv%.x %f2,%0\"; +}") + +(define_expand "negxf2" + [(set (match_operand:XF 0 "general_operand" "") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" "")))] + "" + " +{ + /* ??? There isn't an FPA define_insn so we could handle it here too. + For now we don't (paranoia). */ + if (!TARGET_68881) + { + rtx result; + rtx target; + rtx insns; + + start_sequence (); + target = operand_subword (operands[0], 0, 1, XFmode); + result = expand_binop (SImode, xor_optab, + operand_subword_force (operands[1], 0, XFmode), + GEN_INT(0x80000000), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + emit_move_insn (operand_subword (operands[0], 1, 1, XFmode), + operand_subword_force (operands[1], 1, XFmode)); + emit_move_insn (operand_subword (operands[0], 2, 1, XFmode), + operand_subword_force (operands[1], 2, XFmode)); + + insns = get_insns (); + end_sequence (); + + emit_no_conflict_block (insns, operands[0], operands[1], 0, 0); + DONE; + } +}") + +(define_insn "negxf2_68881" + [(set (match_operand:XF 0 "general_operand" "=f") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fneg%.x %1,%0\"; + return \"fneg%.x %f1,%0\"; +}") + +(define_expand "absxf2" + [(set (match_operand:XF 0 "general_operand" "") + (abs:XF (match_operand:XF 1 "nonimmediate_operand" "")))] + "" + " +{ + /* ??? There isn't an FPA define_insn so we could handle it here too. + For now we don't (paranoia). */ + if (!TARGET_68881) + { + rtx result; + rtx target; + rtx insns; + + start_sequence (); + target = operand_subword (operands[0], 0, 1, XFmode); + result = expand_binop (SImode, and_optab, + operand_subword_force (operands[1], 0, XFmode), + GEN_INT(0x7fffffff), target, 0, OPTAB_WIDEN); + if (result == 0) + abort (); + + if (result != target) + emit_move_insn (result, target); + + emit_move_insn (operand_subword (operands[0], 1, 1, XFmode), + operand_subword_force (operands[1], 1, XFmode)); + emit_move_insn (operand_subword (operands[0], 2, 1, XFmode), + operand_subword_force (operands[1], 2, XFmode)); + + insns = get_insns (); + end_sequence (); + + emit_no_conflict_block (insns, operands[0], operands[1], 0, 0); + DONE; + } +}") + +(define_insn "absxf2_68881" + [(set (match_operand:XF 0 "general_operand" "=f") + (abs:XF (match_operand:XF 1 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "* +{ + if (REG_P (operands[1]) && ! DATA_REG_P (operands[1])) + return \"fabs%.x %1,%0\"; + return \"fabs%.x %f1,%0\"; +}") + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (sqrt:XF (match_operand:XF 1 "nonimmediate_operand" "fm")))] + "TARGET_68881" + "fsqrt%.x %1,%0") + +(define_insn "sinsf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (unspec:SF [(match_operand:SF 1 "general_operand" "fm")] 1))] + "TARGET_68881 && flag_fast_math" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsin%.x %1,%0\"; + else + return \"fsin%.s %1,%0\"; +}") + +(define_insn "sindf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (unspec:DF [(match_operand:DF 1 "general_operand" "fm")] 1))] + "TARGET_68881 && flag_fast_math" + "* +{ + if (FP_REG_P (operands[1])) + return \"fsin%.x %1,%0\"; + else + return \"fsin%.d %1,%0\"; +}") + +(define_insn "sinxf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (unspec:XF [(match_operand:XF 1 "nonimmediate_operand" "fm")] 1))] + "TARGET_68881 && flag_fast_math" + "fsin%.x %1,%0") + +(define_insn "cossf2" + [(set (match_operand:SF 0 "general_operand" "=f") + (unspec:SF [(match_operand:SF 1 "general_operand" "fm")] 2))] + "TARGET_68881 && flag_fast_math" + "* +{ + if (FP_REG_P (operands[1])) + return \"fcos%.x %1,%0\"; + else + return \"fcos%.s %1,%0\"; +}") + +(define_insn "cosdf2" + [(set (match_operand:DF 0 "general_operand" "=f") + (unspec:DF [(match_operand:DF 1 "general_operand" "fm")] 2))] + "TARGET_68881 && flag_fast_math" + "* +{ + if (FP_REG_P (operands[1])) + return \"fcos%.x %1,%0\"; + else + return \"fcos%.d %1,%0\"; +}") + +(define_insn "cosxf2" + [(set (match_operand:XF 0 "general_operand" "=f") + (unspec:XF [(match_operand:XF 1 "nonimmediate_operand" "fm")] 2))] + "TARGET_68881 && flag_fast_math" + "fcos%.x %1,%0") diff --git a/gcc/config/m68k/m68kelf.h b/gcc/config/m68k/m68kelf.h new file mode 100755 index 0000000..0257d1b --- /dev/null +++ b/gcc/config/m68k/m68kelf.h @@ -0,0 +1,297 @@ +/* m68kelf support, derived from m68kv4.h */ + +/* Target definitions for GNU compiler for mc680x0 running System V.4 + Copyright (C) 1991, 1993 Free Software Foundation, Inc. + + Written by Ron Guilmette (rfg@netcom.com) and Fred Fish (fnf@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* #notinclude "m68k/sgs.h" /* The m68k/SVR4 assembler is SGS based */ + +/* These are necessary for -fpic/-fPIC to work correctly. */ +#ifndef MOTOROLA +#define MOTOROLA /* Use MOTOROLA syntax. */ +#endif +#ifdef USE_GAS /* when present, forces jsbr instead of jsr. */ +#undef USE_GAS +#endif + +#ifndef SWBEG_ASM_OP +#define SWBEG_ASM_OP ".swbeg" +#endif + +/* Here are four prefixes that are used by asm_fprintf to + facilitate customization for alternate assembler syntaxes. + Machines with no likelihood of an alternate syntax need not + define these and need not use asm_fprintf. */ + +/* The prefix for register names. Note that REGISTER_NAMES + is supposed to include this prefix. Also note that this is NOT an + fprintf format string, it is a literal string */ + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +/* The prefix for local (compiler generated) labels. + These labels will not appear in the symbol table. */ + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* The prefix for immediate operands. */ + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "#" + +/* In the machine description we can't use %R, because it will not be seen + by ASM_FPRINTF. (Isn't that a design bug?). */ + +#undef REGISTER_PREFIX_MD +#define REGISTER_PREFIX_MD "%%" + +/* config/m68k.md has an explicit reference to the program counter, + prefix this by the register prefix. */ + +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp %%pc@(2,%0:l)"; \ + else \ + return "jmp %%pc@(2,%0:w)"; \ + } while (0) + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number. + Motorola format uses different register names than defined + in m68k.h. */ + +#undef REGISTER_NAMES + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7" } + +/* This is how to output an assembler line that says to advance the + location counter to a multiple of 2**LOG bytes. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) > 0) \ + fprintf ((FILE), "\t%s \t%u\n", ALIGN_ASM_OP, 1 << (LOG)); \ + else if ((LOG) > 31) \ + abort (); + +/* Use proper assembler syntax for these macros. */ +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + asm_fprintf (FILE, "\t%Omove.l %s,-(%Rsp)\n", reg_names[REGNO]) + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + asm_fprintf (FILE, "\t%Omove.l (%Rsp)+,%s\n", reg_names[REGNO]) + +/* Override the definition of NO_DOLLAR_IN_LABEL in svr4.h, for special + g++ assembler names. When this is defined, g++ uses embedded '.' + characters and some m68k assemblers have problems with this. The + chances are much greater that any particular assembler will permit + embedded '$' characters. */ + +#undef NO_DOLLAR_IN_LABEL + +/* Define PCC_STATIC_STRUCT_RETURN if the convention on the target machine + is to use the nonreentrant technique for returning structure and union + values, as commonly implemented by the AT&T Portable C Compiler (PCC). + When defined, the gcc option -fpcc-struct-return can be used to cause + this form to be generated. When undefined, the option does nothing. + For m68k SVR4, the convention is to use a reentrant technique compatible + with the gcc default, so override the definition of this macro in m68k.h */ + +#undef PCC_STATIC_STRUCT_RETURN + +/* Local common symbols are declared to the assembler with ".lcomm" rather + than ".bss", so override the definition in svr4.h */ + +#undef BSS_ASM_OP +#define BSS_ASM_OP ".lcomm" + +/* Register in which address to store a structure value is passed to a + function. The default in m68k.h is a1. For m68k/SVR4 it is a0. */ + +#undef STRUCT_VALUE_REGNUM +#define STRUCT_VALUE_REGNUM 8 + +#define ASM_COMMENT_START "|" + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" + +/* Define how the m68k registers should be numbered for Dwarf output. + The numbering provided here should be compatible with the native + SVR4 SDB debugger in the m68k/SVR4 reference port, where d0-d7 + are 0-7, a0-a8 are 8-15, and fp0-fp7 are 16-23. */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* The ASM_OUTPUT_SKIP macro is first defined in m68k.h, using ".skip". + It is then overridden by m68k/sgs.h to use ".space", and again by svr4.h + to use ".zero". The m68k/SVR4 assembler uses ".space", so repeat the + definition from m68k/sgs.h here. Note that ASM_NO_SKIP_IN_TEXT is + defined in m68k/sgs.h, so we don't have to repeat it here. */ + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t%s %u\n", SPACE_ASM_OP, (SIZE)) + +#if 0 +/* SVR4 m68k assembler is bitching on the `comm i,1,1' which askes for + 1 byte alignment. Don't generate alignment for COMMON seems to be + safer until we the assembler is fixed. */ +#undef ASM_OUTPUT_ALIGNED_COMMON +/* Same problem with this one. */ +#undef ASM_OUTPUT_ALIGNED_LOCAL +#endif + +/* The `string' directive on m68k svr4 does not handle string with + escape char (ie., `\') right. Use normal way to output ASCII bytes + seems to be safer. */ +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +do { \ + register int sp = 0, lp = 0, ch; \ + fprintf ((FILE), "\t%s ", BYTE_ASM_OP); \ + do { \ + ch = (PTR)[sp]; \ + if (ch > ' ' && ! (ch & 0x80) && ch != '\\') \ + { \ + fprintf ((FILE), "'%c", ch); \ + } \ + else \ + { \ + fprintf ((FILE), "0x%x", ch); \ + } \ + if (++sp < (LEN)) \ + { \ + if ((sp % 10) == 0) \ + { \ + fprintf ((FILE), "\n\t%s ", BYTE_ASM_OP); \ + } \ + else \ + { \ + putc (',', (FILE)); \ + } \ + } \ + } while (sp < (LEN)); \ + putc ('\n', (FILE)); \ +} while (0) + +/* SVR4 m68k assembler is bitching on the syntax `2.b'. + So use the "LLDnnn-LLnnn" format. Define LLDnnn after the table. */ + +#undef ASM_OUTPUT_CASE_END +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +do { \ + if (switch_table_difference_label_flag) \ + asm_fprintf ((FILE), "\t%s %LLD%d,%LL%d\n", SET_ASM_OP, (NUM), (NUM));\ + switch_table_difference_label_flag = 0; \ +} while (0) + +extern int switch_table_difference_label_flag; + +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* Currently, JUMP_TABLES_IN_TEXT_SECTION must be defined in order to + keep switch tables in the text section. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Override the definition in svr4.h. In m68k svr4, using swbeg is the + standard way to do switch table. */ +#undef ASM_OUTPUT_BEFORE_CASE_LABEL +#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf ((FILE), "\t%s &%d\n", SWBEG_ASM_OP, XVECLEN (PATTERN (TABLE), 1)); + +/* In m68k svr4, a symbol_ref rtx can be a valid PIC operand if it is an + operand of a function call. */ +#undef LEGITIMATE_PIC_OPERAND_P +#define LEGITIMATE_PIC_OPERAND_P(X) \ + (! symbolic_operand (X, VOIDmode) \ + || ((GET_CODE(X) == SYMBOL_REF) && SYMBOL_REF_FLAG(X))) + +/* Turn off function cse if we are doing PIC. We always want function call + to be done as `bsr foo@PLTPC', so it will force the assembler to create + the PLT entry for `foo'. Doing function cse will cause the address of `foo' + to be loaded into a register, which is exactly what we want to avoid when + we are doing PIC on svr4 m68k. */ +#undef OVERRIDE_OPTIONS +#define OVERRIDE_OPTIONS \ +{ \ + if (flag_pic) flag_no_function_cse = 1; \ + if (! TARGET_68020 && flag_pic == 2) \ + error("-fPIC is not currently supported on the 68000 or 68010\n"); \ +} +/* end of stuff from m68kv4.h */ + +#undef SGS_CMP_ORDER + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crtbegin.o%s" + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as + uninitialized global data. If not defined, and neither + `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, + uninitialized global data will be output in the data section if + `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be + used. */ +#ifndef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP ".section\t.bss" +#endif + +/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a + separate, explicit argument. If you define this macro, it is used + in place of `ASM_OUTPUT_BSS', and gives you more flexibility in + handling the required alignment of the variable. The alignment is + specified as the number of bits. + + Try to use function `asm_output_aligned_bss' defined in file + `varasm.c' when defining this macro. */ +#ifndef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) +#endif diff --git a/gcc/config/m68k/m68kemb.h b/gcc/config/m68k/m68kemb.h new file mode 100755 index 0000000..9fa0c69 --- /dev/null +++ b/gcc/config/m68k/m68kemb.h @@ -0,0 +1,55 @@ +/* Definitions of target machine for GNU compiler. "embedded" 68XXX. + This is meant to be included after m68k.h. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. */ + +#define PTRDIFF_TYPE "long int" +#define SIZE_TYPE "long unsigned int" + +/* In order for bitfields to work on a 68000, or with -mnobitfield, we must + define either PCC_BITFIELD_TYPE_MATTERS or STRUCTURE_SIZE_BOUNDARY. + Defining STRUCTURE_SIZE_BOUNDARY results in structure packing problems, + so we define PCC_BITFIELD_TYPE_MATTERS. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Undef PCC_STATIC_STRUCT_RETURN so that we get a re-entrant calling + convention. */ +#undef PCC_STATIC_STRUCT_RETURN + +/* Don't default to pcc-struct-return, so that we can return small structures + and unions in registers, which is slightly more efficient. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Return floating point values in a fp register. This make fp code a + little bit faster. It also makes -msoft-float code incompatible with + -m68881 code, so people have to be careful not to mix the two. */ +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), \ + ((TARGET_68881 \ + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode)) \ + ? 16 : 0)) + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (TARGET_68881 && (N) == 16)) + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -D__embedded__ -Asystem(embedded) \ + -Amachine(mc68000)" + +/* Override the default LIB_SPEC from gcc.c. We don't currently support + profiling, or libg.a. */ + +#undef LIB_SPEC +#define LIB_SPEC "-lc" + +/* Make this be null, since we want the crt0.o to come from the linker + script */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" diff --git a/gcc/config/m68k/m68kv4.h b/gcc/config/m68k/m68kv4.h new file mode 100755 index 0000000..16cc1c9 --- /dev/null +++ b/gcc/config/m68k/m68kv4.h @@ -0,0 +1,346 @@ +/* Target definitions for GNU compiler for mc680x0 running System V.4 + Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Contributed by Ron Guilmette (rfg@monkeys.com) and + Fred Fish (fnf@cygnus.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Use SGS_* macros to control compilation in m68k.md */ + +#define SGS_SWITCH_TABLES /* Different switch table handling */ + +#include "m68k/sgs.h" /* The m68k/SVR4 assembler is SGS based */ + +/* The SGS assembler requires a special definition of + ASM_IDENTIFY_GCC. We combine the m68k/sgs.h and the svr4.h + definitions below. */ +#undef ASM_IDENTIFY_GCC + +#include "svr4.h" /* Pick up the generic SVR4 macros */ + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* When using an SGS assembler, modify the name of the artificial label which + identifies this file as having been compiled with gcc, and the macro that + emits such a label in the assembly output, to use '%' rather than '.' */ + +#undef ASM_IDENTIFY_GCC +#define ASM_IDENTIFY_GCC(FILE) \ +do \ + { \ + if (write_symbols != DBX_DEBUG) \ + fputs ("gcc2_compiled%:\n", FILE); \ + } \ +while (0) + +/* Override the definition of NO_DOLLAR_IN_LABEL in svr4.h, for special + g++ assembler names. When this is defined, g++ uses embedded '.' + characters and some m68k assemblers have problems with this. The + chances are much greater that any particular assembler will permit + embedded '$' characters. */ + +#undef NO_DOLLAR_IN_LABEL + +/* Define PCC_STATIC_STRUCT_RETURN if the convention on the target machine + is to use the nonreentrant technique for returning structure and union + values, as commonly implemented by the AT&T Portable C Compiler (PCC). + When defined, the gcc option -fpcc-struct-return can be used to cause + this form to be generated. When undefined, the option does nothing. + For m68k SVR4, the convention is to use a reentrant technique compatible + with the gcc default, so override the definition of this macro in m68k.h */ + +#undef PCC_STATIC_STRUCT_RETURN + +/* Provide a set of pre-definitions and pre-assertions appropriate for + the m68k running svr4. __svr4__ is our extension. */ + +#define CPP_PREDEFINES \ + "-Dm68k -Dunix -D__svr4__ -D__motorola__ \ + -Asystem(unix) -Asystem(svr4) -Acpu(m68k) -Amachine(m68k)" + +/* Test to see if the target includes a 68881 by default, and use CPP_SPEC + to control whether or not __HAVE_68881__ is defined by default or not. + If a 68881 is the default, gcc will use inline 68881 instructions, by + predefining __HAVE_68881__, unless -msoft-float is specified. + If a 68881 is not the default, gcc will only define __HAVE_68881__ if + -m68881 is specified. */ + +#if TARGET_DEFAULT & MASK_68881 +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" +#else +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" +#endif + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. We override the definition in m68k.h + and match the way the native m68k/SVR4 compiler does profiling, with the + address of the profile counter in a1, not a0, and using bsr rather + than jsr. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + asm_fprintf ((FILE), "\tlea.l\t(%LLP%d,%Rpc),%Ra1\n\tbsr\t_mcount\n", \ + (LABELNO)) + +/* Local common symbols are declared to the assembler with ".lcomm" rather + than ".bss", so override the definition in svr4.h */ +/* ??? svr4.h no longer defines this, and this is only used by m68k/amix.h. */ + +#undef BSS_ASM_OP +#define BSS_ASM_OP ".lcomm" + +/* Register in which address to store a structure value is passed to a + function. The default in m68k.h is a1. For m68k/SVR4 it is a0. */ + +#undef STRUCT_VALUE_REGNUM +#define STRUCT_VALUE_REGNUM 8 + +/* Register in which static-chain is passed to a function. The + default in m68k.h is a0, but that is already the struct value + regnum. Make it a1 instead. */ + +#undef STATIC_CHAIN_REGNUM +#define STATIC_CHAIN_REGNUM 9 + +#define ASM_COMMENT_START "#" + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" + +/* Define how the m68k registers should be numbered for Dwarf output. + The numbering provided here should be compatible with the native + SVR4 SDB debugger in the m68k/SVR4 reference port, where d0-d7 + are 0-7, a0-a8 are 8-15, and fp0-fp7 are 16-23. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +/* The ASM_OUTPUT_SKIP macro is first defined in m68k.h, using ".skip". + It is then overridden by m68k/sgs.h to use ".space", and again by svr4.h + to use ".zero". The m68k/SVR4 assembler uses ".space", so repeat the + definition from m68k/sgs.h here. Note that ASM_NO_SKIP_IN_TEXT is + defined in m68k/sgs.h, so we don't have to repeat it here. */ + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t%s %u\n", SPACE_ASM_OP, (SIZE)) + +/* 1 if N is a possible register number for a function value. + For m68k/SVR4 allow d0, a0, or fp0 as return registers, for integral, + pointer, or floating types, respectively. Reject fp0 if not using a + 68881 coprocessor. */ + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (N) == 8 || (TARGET_68881 && (N) == 16)) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 + +/* Define how to generate (in the callee) the output value of a function + and how to find (in the caller) the value returned by a function. VALTYPE + is the data type of the value (as a tree). If the precise function being + called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. + For m68k/SVR4 generate the result in d0, a0, or fp0 as appropriate. */ + +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_68881 \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : (POINTER_TYPE_P (VALTYPE) \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0))) + +/* For compatibility with the large body of existing code which does not + always properly declare external functions returning pointer types, the + m68k/SVR4 convention is to copy the value returned for pointer functions + from a0 to d0 in the function epilogue, so that callers that have + neglected to properly declare the callee can still find the correct return + value. */ + +extern int current_function_returns_pointer; +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ +do { \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\tmov.l %Ra0,%Rd0\n"); \ +} while (0); + +/* Define how to find the value returned by a library function assuming the + value has mode MODE. + For m68k/SVR4 look for integer values in d0, pointer values in d0 + (returned in both d0 and a0), and floating values in fp0. */ + +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + ((((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode) \ + && TARGET_68881) \ + ? gen_rtx (REG, (MODE), 16) \ + : gen_rtx (REG, (MODE), 0)) + +/* Boundary (in *bits*) on which stack pointer should be aligned. + The m68k/SVR4 convention is to keep the stack pointer longword aligned. */ + +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. + For m68k/SVR4, this is the next longword boundary. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. + For m68k/SVR4, some types (doubles for example) are aligned on 8 byte + boundaries */ + +#undef BIGGEST_ALIGNMENT +#define BIGGEST_ALIGNMENT 64 + +/* SVR4 m68k assembler is bitching on the `comm i,1,1' which asks for + 1 byte alignment. Don't generate alignment for COMMON seems to be + safer until we the assembler is fixed. */ +#undef ASM_OUTPUT_ALIGNED_COMMON +/* Same problem with this one. */ +#undef ASM_OUTPUT_ALIGNED_LOCAL + +/* The `string' directive on m68k svr4 does not handle string with + escape char (ie., `\') right. Use normal way to output ASCII bytes + seems to be safer. */ +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +do { \ + register int sp = 0, lp = 0, ch; \ + fprintf ((FILE), "\t%s ", BYTE_ASM_OP); \ + do { \ + ch = (PTR)[sp]; \ + if (ch > ' ' && ! (ch & 0x80) && ch != '\\') \ + { \ + fprintf ((FILE), "'%c", ch); \ + } \ + else \ + { \ + fprintf ((FILE), "0x%x", ch); \ + } \ + if (++sp < (LEN)) \ + { \ + if ((sp % 10) == 0) \ + { \ + fprintf ((FILE), "\n\t%s ", BYTE_ASM_OP); \ + } \ + else \ + { \ + putc (',', (FILE)); \ + } \ + } \ + } while (sp < (LEN)); \ + putc ('\n', (FILE)); \ +} while (0) + +/* SVR4 m68k assembler is bitching on the syntax `2.b'. + So use the "LLDnnn-LLnnn" format. Define LLDnnn after the table. */ + +#undef ASM_OUTPUT_CASE_END +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +do { \ + if (switch_table_difference_label_flag) \ + asm_fprintf ((FILE), "\t%s %LLD%d,%LL%d\n", SET_ASM_OP, (NUM), (NUM));\ + switch_table_difference_label_flag = 0; \ +} while (0) + +int switch_table_difference_label_flag; + +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs (".lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) + +/* Override the definition in svr4.h. In m68k svr4, using swbeg is the + standard way to do switch table. */ +#undef ASM_OUTPUT_BEFORE_CASE_LABEL +#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf ((FILE), "\t%s &%d\n", SWBEG_ASM_OP, XVECLEN (PATTERN (TABLE), 1)); + +/* In m68k svr4, a symbol_ref rtx can be a valid PIC operand if it is an + operand of a function call. */ +#undef LEGITIMATE_PIC_OPERAND_P +#define LEGITIMATE_PIC_OPERAND_P(X) \ + ((! symbolic_operand (X, VOIDmode) \ + && ! (GET_CODE (X) == CONST_DOUBLE && CONST_DOUBLE_MEM (X) \ + && GET_CODE (CONST_DOUBLE_MEM (X)) == MEM \ + && symbolic_operand (XEXP (CONST_DOUBLE_MEM (X), 0), VOIDmode))) \ + || (GET_CODE (X) == SYMBOL_REF && SYMBOL_REF_FLAG (X))) + +/* Turn off function cse if we are doing PIC. We always want function call + to be done as `bsr foo@PLTPC', so it will force the assembler to create + the PLT entry for `foo'. Doing function cse will cause the address of `foo' + to be loaded into a register, which is exactly what we want to avoid when + we are doing PIC on svr4 m68k. */ +#undef OVERRIDE_OPTIONS +#define OVERRIDE_OPTIONS \ +{ \ + if (flag_pic) flag_no_function_cse = 1; \ + if (! TARGET_68020 && flag_pic == 2) \ + error("-fPIC is not currently supported on the 68000 or 68010\n"); \ +} + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. */ + +/* On m68k svr4, the trampoline is different from the generic version + in that we use a1 as the static call chain. */ + +#undef TRAMPOLINE_TEMPLATE +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + ASM_OUTPUT_SHORT (FILE, GEN_INT (0x227a)); \ + ASM_OUTPUT_SHORT (FILE, GEN_INT (8)); \ + ASM_OUTPUT_SHORT (FILE, GEN_INT (0x2f3a)); \ + ASM_OUTPUT_SHORT (FILE, GEN_INT (8)); \ + ASM_OUTPUT_SHORT (FILE, GEN_INT (0x4e75)); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ + ASM_OUTPUT_INT (FILE, const0_rtx); \ +} + +/* Redefine since we are using a different trampoline */ +#undef TRAMPOLINE_SIZE +#define TRAMPOLINE_SIZE 18 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ + +#undef INITIALIZE_TRAMPOLINE +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 10)), CXT); \ + emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 14)), FNADDR); \ +} diff --git a/gcc/config/m68k/mot3300-crt0.S b/gcc/config/m68k/mot3300-crt0.S new file mode 100755 index 0000000..6a32dc2 --- /dev/null +++ b/gcc/config/m68k/mot3300-crt0.S @@ -0,0 +1,98 @@ +/* The start module crt0.s for the SysV68 Motorola 3300 Delta Series. + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Manfred Hollstein (manfred@lts.sel.alcatel.de). + +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. */ + +#ifdef MOTOROLA +# define COMM comm +# define DATA data +# define EVEN even +# define FILE(n) file n +# define GLOBAL_SYM(s) global s +# define LOCAL_LABEL(l) L%##l +# define IDENT(s) ident s +# define TEXT text +#else /* Assume we are using GNU as. */ +# define COMM .comm +# define DATA .data +# define EVEN .even +# define FILE(name) .file name +# define GLOBAL_SYM(s) .globl s +# define LOCAL_LABEL(l) .L.##l +# define IDENT(s) .section .comment;.asciz s +# define TEXT .text +#endif + + FILE ("crt0.s") + TEXT + GLOBAL_SYM (_start) +_start: mov.l %d0,splimit% + subq.w &8,%sp + mov.l 8(%sp),(%sp) + lea 12(%sp),%a0 + mov.l %a0,4(%sp) + mov.l %a0,%a1 +LOCAL_LABEL(0): + tst.l (%a0)+ + bne.b LOCAL_LABEL(0) +#ifdef SGS_CMP_ORDER + cmpa.l %a0,(%a1) +#else + cmpa.l (%a1),%a0 +#endif + blt.b LOCAL_LABEL(1) + subq.w &4,%a0 +LOCAL_LABEL(1): + mov.l %a0,8(%sp) + mov.l %a0,environ + jsr initfpu + + subq.w &8,%sp + clr.l %d0 /* if (! isatty (fileno (stderr))) */ + mov.b _iob+27,%d0 + mov.l %d0,-(%sp) + jsr isatty + addq.w &4,%sp + tst.l %d0 + bne.b LOCAL_LABEL(isatty) + clr.l -(%sp) /* setbuf (stderr, NULL) */ + pea _iob+28 + jsr setbuf + addq.w &8,%sp +LOCAL_LABEL(isatty): + addq.w &8,%sp + + jsr main + mov.l %d0,(%sp) + jsr exit + moveq.l &1,%d0 + trap &0 + nop + + GLOBAL_SYM (__stop_monitor) +__stop_monitor: + rts + EVEN + + COMM splimit%,4 + COMM environ,4 + + IDENT ("$Id: mot3300-crt0.S,v 1.23 1999/01/15 07:37:19 law Exp $") + IDENT ("Contributed by Manfred Hollstein (manfred@lts.sel.alcatel.de)") + IDENT ("Corrections by Philippe De Muyter (phdm@macqel.be)") diff --git a/gcc/config/m68k/mot3300.h b/gcc/config/m68k/mot3300.h new file mode 100755 index 0000000..e1b4060 --- /dev/null +++ b/gcc/config/m68k/mot3300.h @@ -0,0 +1,816 @@ +/* Definitions of target machine for GNU compiler, + SysV68 Motorola 3300 Delta Series. + Copyright (C) 1987, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. + Contributed by Abramo and Roberto Bagnara (bagnara@dipisa.di.unipi.it) + based on Alex Crain's 3B1 definitions. + Maintained by Philippe De Muyter (phdm@info.ucl.ac.be). + Support for GAS added by merging mot3300g.h into this file by + Manfred Hollstein (manfred@lts.sel.alcatel.de). + +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. */ + +#ifndef USE_GAS +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define MOTOROLA_BSR /* Use Span-dependent optimized bsr */ +#define SGS /* Uses SGS assembler */ +#define SGS_CMP_ORDER /* Takes cmp operands in reverse order */ +#define SGS_SWAP_W /* Use swap.w rather than just plain swap */ +#endif /* USE_GAS */ + +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL + +#include "m68k/m68k.h" + +/* See m68k.h. 0407 means 68020-68040. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_68040|MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* -m[c]6800 requires special flag to the assembler. */ + +#undef ASM_SPEC +#ifndef USE_GAS +#define ASM_SPEC "%{m68000:-p 000}%{mc68000:-p 000}" +#else /* USE_GAS */ +#define ASM_SPEC \ + "%{v:-v} %{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" +#endif /* USE_GAS */ + +/* NYI: FP= is equivalent to -msoft-float */ + +/* We use /lib/libp/lib* when profiling. */ + +/* NYI: if FP=M68881U library is -lc881u */ +/* NYI: if FP= library is -lc. */ +/* Default for us: FP=M68881 library is -lc881 */ +#undef LIB_SPEC +#define LIB_SPEC "%{!shlib:%{!msoft-float:-lc881}%{msoft-float:-lc}}" +#ifdef CROSS_COMPILE +#ifndef USE_GLD +#define DEFAULT_A_OUT_NAME "m68ka.out" +#endif +#endif + +#ifdef USE_GLD +#undef LINK_SPEC +#define LINK_SPEC "%{v:-v}" +#endif /* defined (USE_GLD) */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}\ +%{!mc68000:%{!m68000: -D__mc68020__}}" + +/* Shared libraries need to use crt0s.o */ + +#undef STARTFILE_SPEC +#ifdef CROSS_COMPILE +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} %{p:-L"TOOLDIR_BASE_PREFIX DEFAULT_TARGET_MACHINE"/lib/libp} %{pg:-L"TOOLDIR_BASE_PREFIX DEFAULT_TARGET_MACHINE"/lib/libp} " +#else /* CROSS_COMPILE */ +#define STARTFILE_SPEC \ + "%{!shlib:%{pg:mcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}\ + %{shlib:crt0s.o%s shlib.ifile%s} %{p:-L/usr/lib/libp} %{pg:-L/usr/lib/libp} " +#endif /* CROSS_COMPILE */ + +/* Generate calls to memcpy, memcmp and memset. */ + +#define TARGET_MEM_FUNCTIONS + +/* size_t is unsigned int. */ + +#define SIZE_TYPE "unsigned int" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Follow sysV68 cc regarding alignment imposed by char:0; */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +/* Be compatible with native compiler. */ +#undef PARM_BOUNDARY +#define PARM_BOUNDARY 16 + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* Make output for SDB. */ + +#define SDB_DEBUGGING_INFO + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +#undef LOCAL_LABEL_PREFIX +#ifdef USE_GAS +#define LOCAL_LABEL_PREFIX ".L" +#else +#define LOCAL_LABEL_PREFIX "L%" +#endif + +#undef USER_LABEL_PREFIX + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "&" + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"} + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ + { extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\tmov.l %Ra0,%Rd0\n"); } + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + asm_fprintf (FILE, "\tmov.l %I%LLP%d,%Ra0\n\tjsr mcount%%\n", (LABEL_NO)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#ifndef USE_GAS + +#undef ASM_APP_ON +#define ASM_APP_ON "" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "" + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "text" +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "data" +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP "byte" + +#undef SET_ASM_OP +#define SET_ASM_OP "set" + +#endif /* USE_GAS */ + +#ifdef USE_GLD +/* Support the ctors and dtors sections for g++. */ + +#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"x\"" +#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"x\"" + +/* A list of other sections which the compiler might be "in" at any + given time. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctors, in_dtors + +/* A list of extra section function definitions. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION + +#define CTORS_SECTION_FUNCTION \ +void \ +ctors_section () \ +{ \ + if (in_section != in_ctors) \ + { \ + fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ + in_section = in_ctors; \ + } \ +} + +#define DTORS_SECTION_FUNCTION \ +void \ +dtors_section () \ +{ \ + if (in_section != in_dtors) \ + { \ + fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ + in_section = in_dtors; \ + } \ +} + +/* A C statement (sans semicolon) to output an element in the table of + global constructors. */ +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctors_section (); \ + fprintf (FILE, "\t%s\t ", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtors_section (); \ + fprintf (FILE, "\t%s\t ", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) +#endif /* defined (USE_GLD) */ + +/* The file command should always begin the output. */ + +#undef ASM_FILE_START +#ifndef USE_GAS +#define ASM_FILE_START(FILE) \ + output_file_directive ((FILE), main_input_filename) +#else /* USE_GAS */ +#define ASM_FILE_START(FILE) \ + { \ + fprintf (FILE, "%s", ASM_APP_OFF); \ + output_file_directive ((FILE), main_input_filename); \ + } +#endif /* USE_GAS */ + +/* The sysV68 assembler does not accept dots in labels. + Let's use percent instead */ + +#define ASM_IDENTIFY_GCC(FILE) fputs("gcc2_compiled%:\n", FILE) + +/* Names to predefine in the preprocessor for this target machine. */ +/* ihnp4!lmayk!lgm@eddie.mit.edu says mc68000 and m68k should not be here, + on the other hand I don't care what he says. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dm68k -Dunix -DsysV68 -D__motorola__ -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" + +#undef TARGET_VERSION +#ifndef USE_GAS +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T sysV68 syntax)"); +#endif /* USE_GAS */ + +/* This will return small structs in d0. */ +#define RETURN_IN_MEMORY(type) \ + ((TYPE_MODE (type) == BLKmode) \ + || (AGGREGATE_TYPE_P (type) \ + && GET_MODE_SIZE (TYPE_MODE (type)) > UNITS_PER_WORD)) + +/* Don't default to pcc-struct-return, because we have already specified + exactly how to return structures in the RETURN_IN_MEMORY macro. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* If TARGET_68881, return SF and DF values in fp0 instead of d0. */ +/* NYI: If FP=M68881U return SF and DF values in d0. */ +/* NYI: If -mold return pointer in a0 and d0 */ + +#undef FUNCTION_VALUE +/* sysV68 (brain damaged) cc convention support. */ +#define FUNCTION_VALUE(VALTYPE,FUNC) \ + (TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_68881 \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + : (POINTER_TYPE_P (VALTYPE) \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 8) \ + : gen_rtx (REG, TYPE_MODE (VALTYPE), 0))) + +/* If TARGET_68881, SF and DF values are returned in fp0 instead of d0. */ + +/* Is LIBCALL_VALUE never called with a pointer ? */ +#undef LIBCALL_VALUE +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), \ + ((TARGET_68881 \ + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode)) \ + ? 16 : 0)) + +/* 1 if N is a possible register number for a function value. + d0 may be used, and fp0 as well if -msoft-float is not specified. */ + +#undef FUNCTION_VALUE_REGNO_P +/* sysV68 (brain damaged) cc convention support. */ +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || (N) == 8 || (TARGET_68881 && (N) == 16)) + +/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for + more than one register. */ + +#undef NEEDS_UNTYPED_CALL +#define NEEDS_UNTYPED_CALL 1 + +#ifndef USE_GAS +/* This is the command to make the user-level label named NAME + defined for reference from other files. */ + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "global" +#endif /* USE_GAS */ + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#undef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \ + sprintf ((OUTPUT), "%s_%%%d", (NAME), (LABELNO))) + +#ifdef USE_GAS +#undef ASM_LONG +#define ASM_LONG ".long" +#undef ASM_SHORT +#define ASM_SHORT ".short" +#undef ASM_CHAR +#define ASM_CHAR ".byte" +#undef ASM_BYTE +#define ASM_BYTE ".byte" +#undef ASM_BYTE_OP +#define ASM_BYTE_OP ".byte" +#else +#undef ASM_LONG +#define ASM_LONG "long" +#undef ASM_SHORT +#define ASM_SHORT "short" +#undef ASM_CHAR +#define ASM_CHAR "byte" +#undef ASM_BYTE +#define ASM_BYTE "byte" +#undef ASM_BYTE_OP +#define ASM_BYTE_OP "byte" +#endif /* USE_GAS */ + +/* The sysV68 as doesn't know about double's and float's. */ +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "\t%s 0x%x,0x%x\n", ASM_LONG, l[0], l[1]); \ + } while (0) + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf (FILE, "\t%s 0x%x,0x%x,0x%x\n", ASM_LONG, l[0], l[1], l[2]); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "\t%s 0x%x\n", ASM_LONG, l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\t%s ", ASM_LONG), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\t%s ", ASM_SHORT), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#undef ASM_OUTPUT_CHAR +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\t%s ", ASM_CHAR), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#undef ASM_OUTPUT_BYTE +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\t%s 0x%x\n", ASM_BYTE, (VALUE)) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#ifndef USE_GAS +#define ALIGN_ASM_OP "even" +#else /* USE_GAS */ +#define ALIGN_ASM_OP ".even" +#endif /* USE_GAS */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) >= 1) \ + fprintf (FILE, "\t%s\n", ALIGN_ASM_OP); + +#ifndef USE_GAS +#define SKIP_ASM_OP "space" +#else /* USE_GAS */ +#define SKIP_ASM_OP ".skip" +#endif /* USE_GAS */ + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t%s %u\n", SKIP_ASM_OP, (SIZE)) + +/* Can't use ASM_OUTPUT_SKIP in text section. */ + +#define ASM_NO_SKIP_IN_TEXT 1 + +/* The beginnings of sdb support... */ + +/* Undefining these will allow `output_file_directive' (in toplev.c) + to default to the right thing. */ +#undef ASM_OUTPUT_MAIN_SOURCE_FILENAME +#ifndef USE_GAS +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + do { fprintf (FILE, "\tfile\t"); \ + output_quoted_string (FILE, FILENAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#undef ASM_OUTPUT_SOURCE_LINE +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +/* Yet another null terminated string format. */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + do { register int sp = 0, lp = 0; \ + fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \ + loop: \ + if ((PTR)[sp] > ' ' && ! ((PTR)[sp] & 0x80) && (PTR)[sp] != '\\') \ + { lp += 3; \ + fprintf ((FILE), "'%c", (PTR)[sp]); } \ + else \ + { lp += 5; \ + fprintf ((FILE), "0x%x", (PTR)[sp]); } \ + if (++sp < (LEN)) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf ((FILE), "\n\t%s ", ASCII_DATA_ASM_OP); } \ + else \ + putc (',', (FILE)); \ + goto loop; } \ + putc ('\n', (FILE)); } while (0) +#endif /* USE_GAS */ + +#ifndef USE_GAS +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (r, l); \ + /* Use hex representation even if CODE is f. as needs it. */ \ + fprintf ((FILE), "&0x%lx", l); \ + } while (0) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf ((FILE), "&0x%lx%08lx", l[0], l[1]); \ + } while (0) +#endif /* USE_GAS */ + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%s%d", LOCAL_LABEL_PREFIX, (PREFIX), (NUM)) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + asm_fprintf (FILE, "%L%s%d:\n", PREFIX, NUM) + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ +/* The L after the local prefix is the "L" prefix for the normal labels + generated by gcc; why are ASM_OUTPUT_ADDR_VEC_ELT and + ASM_OUTPUT_ADDR_DIFF_ELT not called with a PREFIX parameter, like + ASM_OUTPUT_INTERNAL_LABEL ? */ + +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + asm_fprintf (FILE, "\t%s %LL%d\n", ASM_LONG, (VALUE)) + +/* This is how to output an element of a case-vector that is relative. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\t%s %LL%d-%LL%d\n", ASM_SHORT, (VALUE), (REL)) + +#ifndef USE_GAS + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + asm_fprintf (FILE, "\tswbeg &%d\n%L%s%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)) + +/* sysV68 as cannot handle LD%n(%pc,%reg) */ +#define SGS_NO_LI + +/* labelno is not used here */ +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "12(%Rpc,%s.", regname) + +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp 8(%%pc,%0.l)"; \ + else \ + return "jmp 8(%%pc,%0.w)"; \ + } while (0) + +#else /* USE_GAS */ + +/* labelno is not used here */ +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%Rpc@(6,%s:", regname) + +#define ASM_RETURN_CASE_JUMP return "jmp %%pc@(2,%0:w)" + +#endif /* USE_GAS */ + +#ifndef USE_GAS + +/* Translate some opcodes to fit the sysV68 assembler syntax. */ +/* The opcodes fdmov and fsmov are guesses. */ + +/* cliffm@netcom.com says no need for .w suffix on jumps. */ +#undef ASM_OUTPUT_OPCODE +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + } \ + else if ((PTR)[0] == 's') \ + { \ + if (!strncmp ((PTR), "swap", 4)) \ + { fprintf ((FILE), "swap.w"); (PTR) += 4; } \ + } \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "f%$move", 7)) \ + { if (TARGET_68040_ONLY) \ + { fprintf ((FILE), "fsmov"); (PTR) += 7; } \ + else \ + { fprintf ((FILE), "fmov"); (PTR) += 7; } } \ + else if (!strncmp ((PTR), "f%&move", 7)) \ + { if (TARGET_68040_ONLY) \ + { fprintf ((FILE), "fdmov"); (PTR) += 7; } \ + else \ + { fprintf ((FILE), "fmov"); (PTR) += 7; } } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbneq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fsne", 4)) \ + { fprintf ((FILE), "fsneq"); (PTR) += 4; } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' \ + || (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'm') (PTR)++; } \ +} +#endif /* USE_GAS */ + +/* phdm@info.ucl.ac.be says to pass SIZE, not ROUNDED. */ + +/* This says how to output an assembler line + to define a global common symbol. */ + +#undef ASM_OUTPUT_COMMON +#ifndef USE_GAS +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) +#else /* USE_GAS */ +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.comm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) +#endif /* USE_GAS */ + +/* This says how to output an assembler line + to define a local common symbol. */ + +#undef ASM_OUTPUT_LOCAL +#ifndef USE_GAS +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) +#else /* USE_GAS */ +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\t.lcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (SIZE))) +#endif /* USE_GAS */ + +#ifndef USE_GAS +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") +#define PUT_SDB_NEXT_DIM(a) fprintf(asm_out_file, "%d,", a) +#define PUT_SDB_LAST_DIM(a) fprintf(asm_out_file, "%d;", a) + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +#endif /* USE_GAS */ + +/* Define subroutines to call to handle multiply, divide, and remainder. + Use the subroutines that the sysV68's library provides. + The `*' prevents an underscore from being prepended by the compiler. */ +/* The '*' is also used by INIT_CUMULATIVE_ARGS */ + +#define DIVSI3_LIBCALL "*ldiv%%" +#define UDIVSI3_LIBCALL "*uldiv%%" +#define MODSI3_LIBCALL "*lrem%%" +#define UMODSI3_LIBCALL "*ulrem%%" +#define MULSI3_LIBCALL "*lmul%%" + +struct sysV68_cumulative_args + { + int offset; + int libcall; + }; + +#undef CUMULATIVE_ARGS +#define CUMULATIVE_ARGS struct sysV68_cumulative_args + +#undef INIT_CUMULATIVE_ARGS +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ +do {(CUM).offset = 0;\ +(CUM).libcall = (LIBNAME) && (*XSTR((LIBNAME), 0) == '*');} while(0) + +#undef FUNCTION_ARG_ADVANCE +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + ((CUM).offset += ((MODE) != BLKmode \ + ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ + : (int_size_in_bytes (TYPE) + 3) & ~3)) + +#undef FUNCTION_ARG +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(((CUM).libcall && (CUM).offset == 0) ? gen_rtx(REG, (MODE), 0)\ +: (TARGET_REGPARM && (CUM).offset < 8) ? gen_rtx (REG, (MODE), (CUM).offset / 4) : 0) + +#undef FUNCTION_ARG_PARTIAL_NREGS +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ +((TARGET_REGPARM && (CUM).offset < 8 \ + && 8 < ((CUM).offset + ((MODE) == BLKmode \ + ? int_size_in_bytes (TYPE) \ + : GET_MODE_SIZE (MODE)))) \ + ? 2 - (CUM).offset / 4 : 0) + +#undef FUNCTION_ARG_REGNO_P +#define FUNCTION_ARG_REGNO_P(N) (TARGET_68020 ? 0 : (N) == 0) + +/* manfred@lts.sel.alcatel.de: I believe that most delta machines are configured to have + a 6888[12] FPU for which we need to link -lm881 instead of -lm; define ALT_LIBM to + tell g++.c about that. */ +#define ALT_LIBM "-lm881" + +#if (TARGET_DEFAULT & MASK_68881) /* The default configuration has a 6888[12] FPU. */ +#define MATH_LIBRARY "-lm881" +#endif + +/* Currently we do not have the atexit() function, + so take that from libgcc2.c */ + +#define NEED_ATEXIT 1 +#define HAVE_ATEXIT 1 + +#define EXIT_BODY \ + do \ + { \ + __stop_monitor (); \ + _cleanup (); \ + } while (0) + +/* FINALIZE_TRAMPOLINE clears the instruction cache. */ + +#undef FINALIZE_TRAMPOLINE +#define FINALIZE_TRAMPOLINE(TRAMP) \ + if (!TARGET_68040) \ + ; \ + else \ + emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__clear_insn_cache"), \ + 0, VOIDmode, 0) diff --git a/gcc/config/m68k/mot3300Mcrt0.S b/gcc/config/m68k/mot3300Mcrt0.S new file mode 100755 index 0000000..539fe8e --- /dev/null +++ b/gcc/config/m68k/mot3300Mcrt0.S @@ -0,0 +1,142 @@ +/* The start module mcrt0.s for the SysV68 Motorola 3300 Delta Series. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Manfred Hollstein (manfred@lts.sel.alcatel.de). + +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. */ + +#ifdef MOTOROLA +# define COMM comm +# define DATA data +# define EVEN even +# define FILE(n) file n +# define GLOBAL_SYM(s) global s +# define LOCAL_LABEL(l) L%##l +# define IDENT(s) ident s +# define TEXT text +#else /* Assume we are using GNU as. */ +# define COMM .comm +# define DATA .data +# define EVEN .even +# define FILE(name) .file name +# define GLOBAL_SYM(s) .globl s +# define LOCAL_LABEL(l) .L.##l +# define IDENT(s) .section .comment;.asciz s +# define TEXT .text +#endif + + FILE ("mcrt0.s") + TEXT + GLOBAL_SYM (_start) +_start: mov.l %d0,splimit% + subq.w &8,%sp + mov.l 8(%sp),(%sp) + lea 12(%sp),%a0 + mov.l %a0,___Argv + mov.l %a0,4(%sp) + mov.l %a0,%a1 +LOCAL_LABEL(0): + tst.l (%a0)+ + bne.b LOCAL_LABEL(0) +#ifdef SGS_CMP_ORDER + cmpa.l %a0,(%a1) +#else + cmpa.l (%a1),%a0 +#endif + blt.b LOCAL_LABEL(1) + subq.w &4,%a0 +LOCAL_LABEL(1): + mov.l %a0,8(%sp) + mov.l %a0,environ + jsr initfpu + + sub &8,%sp + clr.l %d0 /* if (! isatty (fileno (stderr))) */ + mov.b _iob+27,%d0 + mov.l %d0,-(%sp) + jsr isatty + addq.w &4,%sp + tst.l %d0 + bne.b LOCAL_LABEL(isatty) + clr.l -(%sp) /* setbuf (stderr, NULL) */ + pea _iob+28 + jsr setbuf + addq.w &8,%sp +LOCAL_LABEL(isatty): + addq.w &8,%sp + + mov.l &600,-(%sp) + mov.l &etext,%d1 + subi.l &LOCAL_LABEL(endofstart),%d1 + addq.l &1,%d1 + bclr &0,%d1 + addi.l &4812,%d1 + asr.l &1,%d1 + mov.l %d1,-(%sp) + add.l %d1,%d1 + mov.l %d1,-(%sp) + jsr sbrk + addq.w &4,%sp +#ifdef SGS_CMP_ORDER + cmpa.l %a0,&-1 +#else + cmpa.l &-1,%a0 +#endif + beq.b LOCAL_LABEL(3) + mov.l %a0,-(%sp) + add.l &12,%a0 + mov.l %a0,_countbase + mov.l &etext,-(%sp) + mov.l &LOCAL_LABEL(endofstart),-(%sp) + jsr monitor + lea 20(%sp),%sp + jsr main + mov.l %d0,(%sp) + jsr exit +_exit: moveq &1,%d0 + trap &0 + + GLOBAL_SYM (__stop_monitor) +__stop_monitor: + clr.l -(%sp) + jsr monitor + add.w &4,%sp + rts + +LOCAL_LABEL(errtxt): + byte 'N,'o,' ,'s,'p,'a,'c,'e,' ,'f,'o,'r,' ,'m,'o,'n + byte 'i,'t,'o,'r,' ,'b,'u,'f,'f,'e,'r,'\n +LOCAL_LABEL(errtxt_end): + + EVEN +LOCAL_LABEL(3): + pea LOCAL_LABEL(errtxt_end)-LOCAL_LABEL(errtxt) + pea LOCAL_LABEL(errtxt)(%pc) + pea 2 + jsr write + bra.b _exit +LOCAL_LABEL(endofstart): + + EVEN + + COMM splimit%,4 + COMM environ,4 + COMM _countbase,4 + + IDENT ("$Id: mot3300Mcrt0.S,v 1.23 1999/01/15 07:37:19 law Exp $") + IDENT ("Contributed by Manfred Hollstein (manfred@lts.sel.alcatel.de)") + IDENT ("Corrections by Philippe De Muyter (phdm@macqel.be)") diff --git a/gcc/config/m68k/netbsd.h b/gcc/config/m68k/netbsd.h new file mode 100755 index 0000000..6bd9161 --- /dev/null +++ b/gcc/config/m68k/netbsd.h @@ -0,0 +1,63 @@ +#include <m68k/m68k.h> + +/* Get generic NetBSD definitions. */ + +#include <netbsd.h> + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#undef CPP_SPEC +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__ -D__HAVE_FPU__} %{posix:-D_POSIX_SOURCE}" + +#undef ASM_SPEC +#define ASM_SPEC " %| %{m68030} %{m68040} %{m68060} %{fpic:-k} %{fPIC:-k -K}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dm68k -Dmc68000 -Dmc68020 -D__NetBSD__ -Asystem(unix) -Asystem(NetBSD) -Acpu(m68k) -Amachine(m68k)" + +/* Make gcc agree with <machine/ansi.h> */ + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Do not break .stabs pseudos into continuations. */ + +#define DBX_CONTIN_LENGTH 0 + +/* This is the char to use for continuation (in case we need to turn + continuation back on). */ + +#define DBX_CONTIN_CHAR '?' + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Until they use ELF or something that handles dwarf2 unwinds + and initialization stuff better. */ +#define DWARF2_UNWIND_INFO 0 + diff --git a/gcc/config/m68k/news.h b/gcc/config/m68k/news.h new file mode 100755 index 0000000..f83524c --- /dev/null +++ b/gcc/config/m68k/news.h @@ -0,0 +1,552 @@ +/* Definitions of target machine for GNU compiler. SONY NEWS-OS 4 version. + Copyright (C) 1987, 89, 93, 94, 96, 1997 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. */ + +#ifndef USE_GAS +/* This controls conditionals in m68k.h. */ +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS_NO_LI /* Suppress jump table label usage */ +#endif + +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL + +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Sony, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#ifdef MOTOROLA +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews700 -D__motorola__ -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#else +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews700 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif + +/* These conditionals tested for different submodels, + but they were incorrect since they tested the host rather than the target. + The choice of model shouldn't actually matter. */ + +#if 0 +#ifdef news800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews800 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef news900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews900 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef news1500 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1500 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef news1700 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1700 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef news1800 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1800 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef news1900 +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dmc68030 -Dnews1900 -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" +#endif +#endif + +/* Link with libg.a when debugging, for dbx's sake. */ + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +#if 0 +/* This is to be compatible with types.h. + It was found to be necessary with Newsos 3. */ + +#define SIZE_TYPE "long int" +#endif + +/* Override parts of m68k.h to fit Sony's assembler syntax. */ + +#undef BIGGEST_ALIGNMENT +#undef CALL_USED_REGISTERS +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_PROFILER + +#ifdef MOTOROLA +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef REGISTER_NAMES +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_SKIP +#undef ASM_FORMAT_PRIVATE_NAME +#endif + +#undef ASM_OUTPUT_ALIGN + +/* There is no point aligning anything to a rounder boundary than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* NEWS makes d2, d3, fp2 and fp3 unsaved registers, unlike the Sun system. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0} + +/* NEWS returns floats and doubles in fp0, not d0/d1. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), \ + ((TARGET_68881 \ + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode)) \ + ? 16 : 0)) + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\t.align %d\n", (LOG)) + +#ifdef MOTOROLA + +/* Don't try to define `gcc_compiled.' since the assembler does not + accept symbols with periods. This is no real loss since GDB only + really needs it for parms passed in registers. */ +#define ASM_IDENTIFY_GCC(FILE) + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink fp,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l fp,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink fp,#0\n\tsub.l #%d,sp\n", fsize);\ + } \ + else if (fsize) \ + { \ + int amt = fsize + 4; \ + /* Adding negative number is faster on the 68040. */ \ + if (fsize + 4 < 0x8000) \ + asm_fprintf (FILE, "\tadd.w %0I%d,%Rsp\n", - amt); \ + else \ + asm_fprintf (FILE, "\tadd.l %0I%d,%Rsp\n", - amt); \ + } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem.x #0x%x,-(sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovem.l #0x%x,-(sp)\n", mask); } + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmove.l #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask)) \ + { fprintf (FILE, "\tmove.l #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmove.l (-%d,fp,a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmove.l (-%d,fp),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovem.l (-%d,fp,a0.l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovem.l (sp)+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovem.l (-%d,fp),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem.x (-%d,fp,a0.l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem.x (sp)+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem.x (-%d,fp),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk fp\n"); \ + else if (fsize) \ + { \ + if (fsize + 4 < 0x8000) \ + fprintf (FILE, "\tadd.w #%d,sp\n", fsize + 4); \ + else \ + fprintf (FILE, "\tadd.l #%d,sp\n", fsize + 4); \ + } \ + if (current_function_pops_args) \ + fprintf (FILE, "\trtd #%d\n", current_function_pops_args); \ + else fprintf (FILE, "\trts\n"); } + +/* Difference from m68k.h is in `fp' instead of `a6'. */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7"} + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", reg_names[REGNO]) + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.double 0d%s\n", dstr); \ + } while (0) + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +#if 0 +/* The NEWS assembler in version 3.4 complains about fmove.d, but this + macro proved not to work right. 3.4 is old, so forget about it. */ +#define ASM_OUTPUT_OPCODE(FILE, STRING) \ +{ \ + if (!strncmp (STRING, "fmove.d", 7) \ + && CONSTANT_P (operands[1])) \ + { \ + fprintf (FILE, "fmove.x"); \ + STRING += 7; \ + } \ +} +#endif + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 13), \ + sprintf ((OUTPUT), "%s$$$%d", (NAME), (LABELNO))) + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE == 'f') \ + { \ + char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.9e", dstr); \ + if (REAL_VALUE_ISINF (VALUE) || REAL_VALUE_ISNAN (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0f-99e999"); \ + else \ + fprintf (FILE, "#0f99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + fprintf (FILE, "#0f-0.0"); \ + else \ + fprintf (FILE, "#0f%s", dstr); \ + } \ + else \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf (FILE, "#0x%lx", l); \ + } \ + } while (0) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", dstr ); \ + if (REAL_VALUE_ISINF (VALUE) || REAL_VALUE_ISNAN (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0d-99e999"); \ + else \ + fprintf (FILE, "#0d99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + fprintf (FILE, "#0d-0.0"); \ + else \ + fprintf (FILE, "#0d%s", dstr); \ + } while (0) + +/* Note, long double immediate operands are not actually + generated by m68k.md. */ +#undef ASM_OUTPUT_LONG_DOUBLE_OPERAND +#define ASM_OUTPUT_LONG_DOUBLE_OPERAND(FILE,VALUE) \ + do { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ + asm_fprintf (FILE, "%I0r%s", dstr); \ + } while (0) + +#if 0 +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "-(sp)"); \ + else if (CODE == '+') fprintf (FILE, "(sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(sp)"); \ + else if (CODE == '!') fprintf (FILE, "fpcr"); \ + else if (CODE == '$') {if (TARGET_68040_ONLY) fprintf (FILE, "s");} \ + else if (CODE == '&') {if (TARGET_68040_ONLY) fprintf (FILE, "d");} \ + else if (CODE == '/') \ + ; \ + 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 if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { REAL_VALUE_TYPE r; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + if (CODE == 'f') \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL (r, "%.9e", dstr); \ + if (REAL_VALUE_ISINF (r) || REAL_VALUE_ISNAN (r)) { \ + if (REAL_VALUE_NEGATIVE (r)) \ + fprintf (FILE, "#0f-99e999"); \ + else \ + fprintf (FILE, "#0f99e999"); } \ + else if (REAL_VALUE_MINUS_ZERO (r)) \ + fprintf (FILE, "#0f-0.0"); \ + else \ + fprintf (FILE, "#0f%s", dstr); \ + } \ + else \ + { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (r, l); \ + fprintf (FILE, "#0x%x", l); \ + }} \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == XFmode) \ + { REAL_VALUE_TYPE r; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + ASM_OUTPUT_LONG_DOUBLE_OPERAND (FILE, r); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { REAL_VALUE_TYPE r; char dstr[30]; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + REAL_VALUE_TO_DECIMAL (r, "%.20e", dstr ); \ + if (REAL_VALUE_ISINF (r) || REAL_VALUE_ISNAN (r)) { \ + if (REAL_VALUE_NEGATIVE (r)) \ + fprintf (FILE, "#0d-99e999"); \ + else \ + fprintf (FILE, "#0d99e999"); } \ + else if (REAL_VALUE_MINUS_ZERO (r)) \ + fprintf (FILE, "#0d-0.0"); \ + else \ + fprintf (FILE, "#0d%s", dstr); } \ + else if (CODE == 'b') output_addr_const (FILE, X); \ + else { putc ('#', FILE); output_addr_const (FILE, X); }} +#endif + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%d.b,pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "("); \ + if (addr != 0) { \ + output_addr_const (FILE, addr); \ + putc (',', FILE); } \ + fprintf (FILE, "%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + +#else /* Using GAS, which uses the MIT assembler syntax, like a Sun. */ + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmovl #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#endif /* MOTOROLA */ diff --git a/gcc/config/m68k/news3.h b/gcc/config/m68k/news3.h new file mode 100755 index 0000000..b4a3f41 --- /dev/null +++ b/gcc/config/m68k/news3.h @@ -0,0 +1,6 @@ +#include "m68k/news.h" + +/* This is to be compatible with types.h. + It was found to be necessary with Newsos 3. */ + +#define SIZE_TYPE "long int" diff --git a/gcc/config/m68k/news3gas.h b/gcc/config/m68k/news3gas.h new file mode 100755 index 0000000..7c2d2b0 --- /dev/null +++ b/gcc/config/m68k/news3gas.h @@ -0,0 +1,6 @@ +#include "m68k/newsgas.h" + +/* This is to be compatible with types.h. + It was found to be necessary with Newsos 3. */ + +#define SIZE_TYPE "long int" diff --git a/gcc/config/m68k/newsgas.h b/gcc/config/m68k/newsgas.h new file mode 100755 index 0000000..8dc7801 --- /dev/null +++ b/gcc/config/m68k/newsgas.h @@ -0,0 +1,19 @@ +/* In Sony versions before 3.0, use the GNU Assembler, because the + system's assembler has no way to assemble the difference of two + labels for the displacement in a switch-dispatch instruction. */ + +#define USE_GAS + +/* This is the assembler directive to equate two values. */ + +#undef SET_ASM_OP +#define SET_ASM_OP ".set" + +/* This is how we tell the assembler that a symbol is weak. */ + +#undef ASM_WEAKEN_LABEL +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +#include "m68k/news.h" diff --git a/gcc/config/m68k/next.h b/gcc/config/m68k/next.h new file mode 100755 index 0000000..8391ab5 --- /dev/null +++ b/gcc/config/m68k/next.h @@ -0,0 +1,199 @@ +/* Target definitions for GNU compiler for mc680x0 running NeXTSTEP + Copyright (C) 1989, 90-94, 96, 1997 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 "m68k/m68k.h" +#include "nextstep.h" + +/* See m68k.h. 0407 means 68040 (or 68030 or 68020, with 68881/2). */ + +#define TARGET_DEFAULT (MASK_68040|MASK_BITFIELD|MASK_68881|MASK_68020) + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ + +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dm68k -DNeXT -Dunix -D__MACH__ -D__BIG_ENDIAN__ -D__ARCHITECTURE__=\"m68k\" -Asystem(unix) -Asystem(mach) -Acpu(m68k) -Amachine(m68k) -D_NEXT_SOURCE" + +/* Every structure or union's size must be a multiple of 2 bytes. + (Why isn't this in m68k.h?) */ + +#define STRUCTURE_SIZE_BOUNDARY 16 +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#ifdef REAL_VALUE_TO_TARGET_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { \ + long hex[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, hex); \ + fprintf (FILE, "\t.long 0x%x\n\t.long 0x%x\n", hex[0], hex[1]); \ + } while (0) +#else +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.double 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.double 0r99e999\n"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } \ + } while (0) +#endif + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#ifdef REAL_VALUE_TO_TARGET_SINGLE +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { \ + long hex; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, hex); \ + fprintf (FILE, "\t.long 0x%x\n", hex); \ + } while (0) +#else +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.single 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.single 0r99e999\n"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.single 0r%s\n", dstr); \ + } \ + } while (0) +#endif + +#undef ASM_OUTPUT_FLOAT_OPERAND +#ifdef REAL_VALUE_TO_TARGET_SINGLE +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + long hex; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, hex); \ + fprintf (FILE, "#0%c%x", (CODE) == 'f' ? 'b' : 'x', hex); \ + } while (0) +#else +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do{ \ + if (CODE != 'f') \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I0x%x", l); \ + else \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + else if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.9g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) +#endif + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#ifdef REAL_VALUE_TO_TARGET_DOUBLE +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { \ + long hex[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, hex); \ + fprintf (FILE, "#0b%x%08x", hex[0], hex[1]); \ + } while (0) +#else +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) +#endif + +/* We do not define JUMP_TABLES_IN_TEXT_SECTION, since we wish to keep + the text section pure. There is no point in addressing the jump + tables using pc relative addressing, since they are not in the text + section, so we undefine CASE_VECTOR_PC_RELATIVE. This also + causes the compiler to use absolute addresses in the jump table, + so we redefine CASE_VECTOR_MODE to be SImode. */ + +#undef CASE_VECTOR_MODE +#define CASE_VECTOR_MODE SImode +#undef CASE_VECTOR_PC_RELATIVE + +/* Make sure jump tables have the same alignment as other pointers. */ + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \ +{ ASM_OUTPUT_ALIGN (FILE, 1); ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); } + +/* Don't treat addresses involving labels differently from symbol names. + Previously, references to labels generated pc-relative addressing modes + while references to symbol names generated absolute addressing modes. */ + +#undef GO_IF_INDEXABLE_BASE +#define GO_IF_INDEXABLE_BASE(X, ADDR) \ +{ if (LEGITIMATE_BASE_REG_P (X)) goto ADDR; } + +/* This accounts for the return pc and saved fp on the m68k. */ + +#define OBJC_FORWARDING_STACK_OFFSET 8 +#define OBJC_FORWARDING_MIN_OFFSET 8 + +/* FINALIZE_TRAMPOLINE enables executable stack. The + __enable_execute_stack also clears the insn cache. */ + +#undef FINALIZE_TRAMPOLINE +#define FINALIZE_TRAMPOLINE(TRAMP) \ + emit_library_call(gen_rtx(SYMBOL_REF, Pmode, "__enable_execute_stack"), \ + 0, VOIDmode, 1, memory_address(SImode, (TRAMP)), Pmode) + +/* A C expression used to clear the instruction cache from + address BEG to address END. On NeXTSTEP this i a system trap. */ + +#define CLEAR_INSN_CACHE(BEG, END) \ + asm volatile ("trap #2") + +/* GCC is the primary compiler for NeXTSTEP, so we don't need this. */ +#undef PCC_STATIC_STRUCT_RETURN diff --git a/gcc/config/m68k/next21.h b/gcc/config/m68k/next21.h new file mode 100755 index 0000000..5d18c4e --- /dev/null +++ b/gcc/config/m68k/next21.h @@ -0,0 +1,104 @@ +/* Target definitions for GNU compiler for mc680x0 running NeXTSTEP 2.1 + Copyright (C) 1989, 90, 91, 92, 93, 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. */ + +/* Changed for NeXTStep2.1, Ch. Kranz, 2/94, 3/94 */ + +#include "m68k/next.h" +#include "nextstep21.h" + +/* for #include <mach.h> in libgcc2.c */ +#define NeXTStep21 + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.single 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.single 0r99e999\n"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.single 0r%s\n", dstr); \ + } \ + } while (0) + +/* called from m68k.c line 1881 */ +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do{ \ + if (CODE != 'f') \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I0x%x", l); \ + else \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + else if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.9g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) + diff --git a/gcc/config/m68k/os68000.h b/gcc/config/m68k/os68000.h new file mode 100755 index 0000000..8f88769 --- /dev/null +++ b/gcc/config/m68k/os68000.h @@ -0,0 +1,81 @@ +/* CYGNUS LOCAL ericsson */ +/* Definitions of target machine for GNU compiler. Vxworks 68010 version. + Copyright 1987, 1988, 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "m68k/m68k.h" +#include "aoutos.h" + +/* See m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT 0 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68000}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000" + +/* Prevent error on `-sun2' and `-target sun2' options. */ + +#define CC1_SPEC "%{sun2:} %{target:}" + +#define PTRDIFF_TYPE "int" +#define SIZE_TYPE "unsigned int" +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Specify what to link with. */ + +/* VxWorks does all the library stuff itself. */ + +#define LIB_SPEC "" + +/* Provide required defaults for linker -e. */ + +#define LINK_SPEC "%{!nostdlib:%{!r*:%{!e*:-e start}}}" + +/* VxWorks provides the functionality of crt0.o and friends itself. */ + +#define STARTFILE_SPEC "" + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc/config/m68k/ose68k.h b/gcc/config/m68k/ose68k.h new file mode 100755 index 0000000..ebe8846 --- /dev/null +++ b/gcc/config/m68k/ose68k.h @@ -0,0 +1,45 @@ +/* CYGNUS LOCAL ericsson */ +/* Definitions of target machine for GNU compiler. OSE ^68000/68020 version. + Copyright 1987, 1988, 1992, 1996 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. */ + +/* See m68k.h for the macro values */ +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) + +#include "m68k/m68k-none.h" +#include "aoutos.h" + +#define DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* Provide required defaults for linker -e. */ +#define LINK_SPEC "%{!nostdlib:%{!r*:%{!e*:-e start}}}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* User must provide startfile if desired. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" diff --git a/gcc/config/m68k/pbb.h b/gcc/config/m68k/pbb.h new file mode 100755 index 0000000..41319c2 --- /dev/null +++ b/gcc/config/m68k/pbb.h @@ -0,0 +1,163 @@ +/* Definitions of target machine for GNU compiler. + Citicorp/TTI Unicom PBB version (using GAS with a %-register prefix) + Copyright (C) 1987, 1988, 1990, 1996, 1997 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. */ + +/* Note: This config uses a version of gas with a postprocessing stage that + converts the output of gas to coff containing stab debug symbols. + (See vasta@apollo.com or mb@soldev.tti.com) */ + +#include "m68k/m68k.h" + +/* See m68k.h. 5 means 68020 without 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Every structure or union's size must be a multiple of 2 bytes. */ +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Define __HAVE_68881__ in preprocessor if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dm68k -Dunix -DUnicomPBB -Dmc68k -Dmc68020 -Dmc68k32 -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +/* We want DBX format for use with gdb under COFF. */ + +#define DBX_DEBUGGING_INFO + +/* Generate calls to memcpy, memcmp and memset. */ + +#define TARGET_MEM_FUNCTIONS + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + " %{m68000:-mc68010}%{mc68000:-mc68010}" + +/* we use /lib/libp/lib* when profiling */ + +#define LIB_SPEC "%{p:-L/usr/lib/libp} %{pg:-L/usr/lib/libp} -lc" + + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ +/* + * The loader directive file gcc.ifile defines how to merge the constructor + * sections into the data section. Also, since gas only puts out those + * sections in response to N_SETT stabs, and does not (yet) have a + * ".sections" directive, gcc.ifile also defines the list symbols + * __DTOR_LIST__ and __CTOR_LIST__. + * + * Finally, we must explicitly specify the file from libgcc.a that defines + * exit(), otherwise if the user specifies (for example) "-lc_s" on the + * command line, the wrong exit() will be used and global destructors will + * not get called . + */ + +#define STARTFILE_SPEC \ +"%{!r: gcc.ifile%s} %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} \ +%{!r:_exit.o%s}" + +#define ENDFILE_SPEC "crtn.o%s" + +/* cpp has to support a #sccs directive for the /usr/include files */ + +#define SCCS_DIRECTIVE + +/* GAS register prefix assembly syntax: */ + +/* User labels have no prefix */ +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* local labels are prefixed with ".L" */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* registers are prefixed with "%" */ +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"} + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ + { extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\tmovl %Rd0,%Ra0\n"); } + +#define ASM_RETURN_CASE_JUMP \ + do { \ + if (TARGET_5200) \ + return "ext%.l %0\n\tjmp %%pc@(2,%0:l)"; \ + else \ + return "jmp %%pc@(2,%0:w)"; \ + } while (0) + +/* Although the gas we use can create .ctor and .dtor sections from N_SETT + stabs, it does not support section directives, so we need to have the loader + define the lists. + */ +#define CTOR_LISTS_DEFINED_EXTERNALLY + +/* similar to default, but allows for the table defined by ld with gcc.ifile. + nptrs is always 0. So we need to instead check that __DTOR_LIST__[1] != 0. + The old check is left in so that the same macro can be used if and when + a future version of gas does support section directives. */ + +#define DO_GLOBAL_DTORS_BODY {int nptrs = *(int *)__DTOR_LIST__; int i; \ + if (nptrs == -1 || (__DTOR_LIST__[0] == 0 && __DTOR_LIST__[1] != 0)) \ + for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++); \ + for (i = nptrs; i >= 1; i--) \ + __DTOR_LIST__[i] (); } + +/* + * Here is an example gcc.ifile. I've tested it on PBB 68k and on sco 386 + * systems. The NEXT(0x200000) works on just about all 386 and m68k systems, + * but can be reduced to any power of 2 that is >= NBPS (0x10000 on a pbb). + + SECTIONS { + .text BIND(0x200200) BLOCK (0x200) : + { *(.init) *(.text) vfork = fork; *(.fini) } + + GROUP BIND( NEXT(0x200000) + ADDR(.text) + SIZEOF(.text)): + { .data : { __CTOR_LIST__ = . ; . += 4; *(.ctor) . += 4 ; + __DTOR_LIST__ = . ; . += 4; *(.dtor) . += 4 ; } + .bss : { } + } + } + */ + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gcc/config/m68k/plexus.h b/gcc/config/m68k/plexus.h new file mode 100755 index 0000000..3ca99fd --- /dev/null +++ b/gcc/config/m68k/plexus.h @@ -0,0 +1,108 @@ +/* Definitions of target machine for GNU compiler, for 680X0 based Plexus + Computers running SYSVR2 + Copyright (C) 1990, 1994, 1996 Free Software Foundation, Inc. + Contributed by Randy Welch (rwelch@netcom.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, 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. */ + + +/* The Plexus port of gcc requires you to use gas ( either 1.3X with COFF + patches or 2.X ), If you use gas 2.X you have to use binutils-2.X. + + With using gas-2.X the Plexus gcc port is now capable of generating + output suitable for use by gdb-4.X ( send mail to above address for + info on getting gdb patches or other GNU items for the Plexus ) + + This is configured for label output default by gas as LXXX instead of + plexus cc/as combination requires .LXXX */ + +#include "m68k/m68k.h" + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__}" +#define CPP_PREDEFINES "-Dm68 -Dunix -Dplexus -Asystem(unix) -Acpu(m68k) -Amachine(m68k)" + +#if TARGET_DEFAULT & MASK_68020 +#define ASM_SPEC\ +"%{m68000:-mc68000}%{mc68000:-mc68000}%{!mc68000:%{!m68000:-mc68020}}" +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 +#else +#define ASM_SPEC\ +"%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!mc68020:-mc68000}}" +#endif + +/***************************************************************************/ +/* Un comment the following if you want adb to be able to follow a core */ +/* file if you compile a program with -O */ +/***************************************************************************/ +/* #define FRAME_POINTER_REQUIRED */ + +/* Let's be compatible with the Plexus C compiler by default. Why not? */ +#define PLEXUS_CC_COMPAT + +#ifdef PLEXUS_CC_COMPAT +#define STRUCTURE_SIZE_BOUNDARY 16 /* for compatibility with cc */ +#undef STACK_BOUNDARY +#define STACK_BOUNDARY 32 /* ditto */ +#endif + +#undef NEED_PROBE +#define NEED_PROBE -132 /* plexus needs a stack probe */ + +/***********************************************************************/ +/* if you have binutils-2.X and gas-2.X running you can generate code */ +/* that gdb can understand ( gdb support available for 4.11 ) */ +/* */ +/* If you use gas-1.3X don't define this as the version of the coff */ +/* patches for gas-1.3x ( stabs in coff ) does not generate coff debug */ +/* syms */ +/***********************************************************************/ +#define HAVE_GAS_2_X + +#ifdef HAVE_GAS_2_X +#undef DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + output_file_directive((FILE), main_input_filename) + +#else +#undef DBX_DEBUGGING_INFO /* no real debugger */ +#undef SDB_DEBUGGING_INFO +#endif +#define TARGET_MEM_FUNCTIONS + +/***********************************************************************/ +/* items for collect2 */ +/***********************************************************************/ + +#define NM_FLAGS "" +#define NO_SYS_SIGLIST +#define NO_DUP2 + +#define SIZE_TYPE "int" diff --git a/gcc/config/m68k/rtems.h b/gcc/config/m68k/rtems.h new file mode 100755 index 0000000..20e623e --- /dev/null +++ b/gcc/config/m68k/rtems.h @@ -0,0 +1,33 @@ +/* Definitions for rtems targeting a Motorola m68k using coff. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Joel Sherrill (joel@OARcorp.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "m68k/m68k-coff.h" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -Drtems -D__rtems__ \ + -Asystem(rtems) -Acpu(mc68000) -Acpu(m68k) -Amachine(m68k)" + +/* Generate calls to memcpy, memcmp and memset. */ +#ifndef TARGET_MEM_FUNCTIONS +#define TARGET_MEM_FUNCTIONS +#endif diff --git a/gcc/config/m68k/sgs.h b/gcc/config/m68k/sgs.h new file mode 100755 index 0000000..62d2336 --- /dev/null +++ b/gcc/config/m68k/sgs.h @@ -0,0 +1,446 @@ +/* Definitions of target machine for GNU compiler for m68k targets using + assemblers derived from AT&T "SGS" releases. + Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc. + Written by Fred Fish (fnf@cygnus.com) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, 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. */ + +/* Control assembler-syntax conditionals in m68k.md and conditionals in + m68k.h. Note that some systems may also require SGS_SWAP_W and/or + SGS_SWITCH_TABLES to be defined as well. */ + +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS /* Uses SGS assembler */ +#define SGS_CMP_ORDER /* Takes cmp operands in reverse order */ + +#include "m68k/m68k.h" + +/* SGS specific assembler pseudo ops. */ + +#define BYTE_ASM_OP ".byte" +#define WORD_ASM_OP ".short" +#define LONG_ASM_OP ".long" +#define SPACE_ASM_OP ".space" +#define ALIGN_ASM_OP ".align" +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP ".global" +#define SWBEG_ASM_OP ".swbeg" +#define SET_ASM_OP ".set" + +#define UNALIGNED_SHORT_ASM_OP ".short" /* Used in dwarfout.c */ +#define UNALIGNED_INT_ASM_OP ".long" /* Used in dwarfout.c */ + +#define ASM_PN_FORMAT "%s_%d" /* Format for private names */ + +/* Here are four prefixes that are used by asm_fprintf to + facilitate customization for alternate assembler syntaxes. + Machines with no likelihood of an alternate syntax need not + define these and need not use asm_fprintf. */ + +/* The prefix for register names. Note that REGISTER_NAMES + is supposed to include this prefix. Also note that this is NOT an + fprintf format string, it is a literal string */ + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +/* The prefix for local (compiler generated) labels. + These labels will not appear in the symbol table. */ + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* The prefix for immediate operands. */ + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "&" + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number. + Motorola format uses different register names than defined in m68k.h. + We also take this chance to convert 'a6' to 'fp' */ + +#undef REGISTER_NAMES + +#ifndef SUPPORT_SUN_FPA + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7" } + +#else /* SUPPORTED_SUN_FPA */ + +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", \ + "%fpa0", "%fpa1", "%fpa2", "%fpa3", "%fpa4", "%fpa5", "%fpa6","%fpa7", \ + "%fpa8", "%fpa9", "%fpa10","%fpa11","%fpa12","%fpa13","%fpa14","%fpa15", \ + "%fpa16","%fpa17","%fpa18","%fpa19","%fpa20","%fpa21","%fpa22","%fpa23", \ + "%fpa24","%fpa25","%fpa26","%fpa27","%fpa28","%fpa29","%fpa30","%fpa31" } + +#endif /* defined SUPPORT_SUN_FPA */ + +/* When using an SGS assembler, modify the name of the artificial label which + identifies this file as having been compiled with gcc, and the macro that + emits such a label in the assembly output, to use '%' rather than '.' */ + +#define ASM_IDENTIFY_GCC(FILE) \ + { fprintf ((FILE), "%s:\n", "gcc2_compiled%"); } + +/* This is how to output an assembler line defining an `int' constant. */ +/* The SGS assembler doesn't understand ".word". */ + +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf ((FILE), "\t%s ", WORD_ASM_OP), \ + output_addr_const ((FILE), (VALUE)), \ + fprintf ((FILE), "\n")) + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf ((FILE), "\t%s 0x%x,0x%x,0x%x\n", LONG_ASM_OP, \ + l[0], l[1], l[2]); \ + } while (0) + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf ((FILE), "\t%s 0x%x,0x%x\n", LONG_ASM_OP, \ + l[0], l[1]); \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "\t%s 0x%x\n", LONG_ASM_OP, l); \ + } while (0) + +/* This is how to output an assembler line that says to advance the + location counter to a multiple of 2**LOG bytes. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) > 0) \ + fprintf ((FILE), "\t%s \t%u\n", ALIGN_ASM_OP, 1 << (LOG)); \ + else if ((LOG) > 31) \ + abort (); + +/* The routine used to output null terminated string literals. We cannot + use the ".string" pseudo op, because it silently truncates strings to + 1023 bytes. There is no "partial string op" which works like ".string" + but doesn't append a null byte, so we can't chop the input string up + into small pieces and use that. Our only remaining alternative is to + output the string one byte at a time. */ + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ +do { \ + register int sp = 0, lp = 0, ch; \ + fprintf ((FILE), "\t%s ", BYTE_ASM_OP); \ + do { \ + ch = (PTR)[sp]; \ + if (ch > ' ' && ! (ch & 0x80) && ch != '\\') \ + { \ + fprintf ((FILE), "'%c", ch); \ + } \ + else \ + { \ + fprintf ((FILE), "0x%x", ch); \ + } \ + if (++sp < (LEN)) \ + { \ + if ((sp % 10) == 0) \ + { \ + fprintf ((FILE), "\n\t%s ", BYTE_ASM_OP); \ + } \ + else \ + { \ + putc (',', (FILE)); \ + } \ + } \ + } while (sp < (LEN)); \ + putc ('\n', (FILE)); \ +} while (0) + + +/* SGS based assemblers don't understand #NO_APP and #APP, so just don't + bother emitting them. */ + +#undef ASM_APP_ON +#define ASM_APP_ON "" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "" + +/* When using SGS derived assemblers, change the "MIT" or "MOTOROLA" + to "SGS/AT&T" */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, SGS/AT&T syntax)"); + +/* Use proper assembler syntax for these macros. */ +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + asm_fprintf (FILE, "\t%Omove.l %s,-(%Rsp)\n", reg_names[REGNO]) + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + asm_fprintf (FILE, "\t%Omove.l (%Rsp)+,%s\n", reg_names[REGNO]) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + asm_fprintf ((FILE), "%I0x%x", l); \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + asm_fprintf ((FILE), "%I0x%x%08x", l[0], l[1]); \ + } while (0) + +/* How to output a block of SIZE zero bytes. Note that the `space' pseudo, + when used in the text segment, causes SGS assemblers to output nop insns + rather than 0s, so we set ASM_NO_SKIP_IN_TEXT to prevent this. */ + +#define ASM_NO_SKIP_IN_TEXT 1 + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t%s %u\n", SPACE_ASM_OP, (SIZE)) + +/* Translate Motorola opcodes such as `jbeq' into SGS opcodes such + as `beq.w'. + Delete the `e' in `move...' and `fmove'. + Change `ftst' to `ftest'. + Change `fbne' to `fbneq' + Change `fsne' to `fsneq' + Change `divsl' to `tdivs' (32/32 -> 32r:32q) + Change `divul' to `tdivu' (32/32 -> 32r:32q) + Optionally change swap to swap.w. + */ + +#ifdef SGS_SWAP_W +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ \ + extern int flag_pic; \ + if (!strncmp ((PTR), "jbsr", 4)) \ + { if (flag_pic) \ + fprintf ((FILE), "bsr"); \ + else \ + fprintf ((FILE), "jsr"); \ + (PTR) += 4; } \ + else if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 's') \ + { \ + if (!strncmp ((PTR), "swap", 4)) \ + { fprintf ((FILE), "swap.w"); (PTR) += 4; } \ + } \ +/* FMOVE ==> FMOV, (and F%& F%$ translations) */ \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbneq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fsne", 4)) \ + { fprintf ((FILE), "fsneq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "f%$move", 7)) \ + { (PTR) += 7; \ + if (TARGET_68040_ONLY) \ + fprintf ((FILE), "fsmov"); \ + else fprintf ((FILE), "fmov"); } \ + else if (!strncmp ((PTR), "f%&move", 7)) \ + { (PTR) += 7; \ + if (TARGET_68040_ONLY) \ + fprintf ((FILE), "fdmov"); \ + else fprintf ((FILE), "fmov"); } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' \ + || (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'm') (PTR)++; } \ +/* DIVSL ==> TDIVS */ \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 's' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivs"); (PTR) += 5; } \ +/* DIVUL ==> TDIVU */ \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'u' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivu"); (PTR) += 5; } \ +} + +#else /* not SGS_SWAP_W */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ \ + extern int flag_pic; \ + if (!strncmp ((PTR), "jbsr", 4)) \ + { if (flag_pic) \ + fprintf ((FILE), "bsr"); \ + else \ + fprintf ((FILE), "jsr"); \ + (PTR) += 4; } \ + else if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ +/* FMOVE ==> FMOV, (and F%& F%$ translations) */ \ + else if ((PTR)[0] == 'f') \ + { \ + if (!strncmp ((PTR), "fmove", 5)) \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ + else if (!strncmp ((PTR), "ftst", 4)) \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fbne", 4)) \ + { fprintf ((FILE), "fbneq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "fsne", 4)) \ + { fprintf ((FILE), "fsneq"); (PTR) += 4; } \ + else if (!strncmp ((PTR), "f%$move", 7)) \ + { (PTR) += 7; \ + if (TARGET_68040_ONLY) \ + fprintf ((FILE), "fsmov"); \ + else fprintf ((FILE), "fmov"); } \ + else if (!strncmp ((PTR), "f%&move", 7)) \ + { (PTR) += 7; \ + if (TARGET_68040_ONLY) \ + fprintf ((FILE), "fdmov"); \ + else fprintf ((FILE), "fmov"); } \ + } \ +/* MOVE, MOVEA, MOVEQ, MOVEC ==> MOV */ \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'a' \ + || (PTR)[0] == 'c') (PTR)++; } \ +/* SUB, SUBQ, SUBA, SUBI ==> SUB */ \ + else if ((PTR)[0] == 's' && (PTR)[1] == 'u' \ + && (PTR)[2] == 'b') \ + { fprintf ((FILE), "sub"); (PTR) += 3; \ + if ((PTR)[0] == 'q' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'a') (PTR)++; } \ +/* CMP, CMPA, CMPI, CMPM ==> CMP */ \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p') \ + { fprintf ((FILE), "cmp"); (PTR) += 3; \ + if ((PTR)[0] == 'a' || (PTR)[0] == 'i' \ + || (PTR)[0] == 'm') (PTR)++; } \ +/* DIVSL ==> TDIVS */ \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 's' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivs"); (PTR) += 5; } \ +/* DIVUL ==> TDIVU */ \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'u' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivu"); (PTR) += 5; } \ +} + +#endif /* not SGS_SWAP_W */ + +/* This macro outputs the label at the start of a switch table. The + ".swbeg <N>" is an assembler directive that causes the switch table + size to be inserted into the object code so that disassemblers, for + example, can identify that it is the start of a switch table. */ + +#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf ((FILE), "\t%s &%d\n", SWBEG_ASM_OP, XVECLEN (PATTERN (TABLE), 1)); + +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + do { \ + ASM_OUTPUT_BEFORE_CASE_LABEL((FILE),(PREFIX),(NUM),(TABLE)); \ + ASM_OUTPUT_INTERNAL_LABEL((FILE),(PREFIX),(NUM)); \ + } while (0) + +/* At end of a switch table, define LDnnn iff the symbol LInnn was defined. + Some SGS assemblers have a bug such that "Lnnn-LInnn-2.b(pc,d0.l*2)" + fails to assemble. Luckily "LDnnn(pc,d0.l*2)" produces the results + we want. This difference can be accommodated by making the assembler + define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other + string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END + macro. */ + +#undef ASM_OUTPUT_CASE_END +#define ASM_OUTPUT_CASE_END(FILE,NUM,TABLE) \ +{ if (switch_table_difference_label_flag) \ + asm_fprintf (FILE, "\t%s %LLD%d,%LL%d-%LLI%d-2.b\n",\ + SET_ASM_OP, (NUM), (NUM), (NUM)); \ + switch_table_difference_label_flag = 0; } + +extern int switch_table_difference_label_flag; + +/* This is how to output an element of a case-vector that is relative. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\t%s %LL%d-%LL%d\n", WORD_ASM_OP, VALUE, REL) + +/* Currently, JUMP_TABLES_IN_TEXT_SECTION must be defined in order to + keep switch tables in the text section. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#undef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), ASM_PN_FORMAT, (NAME), (LABELNO))) + diff --git a/gcc/config/m68k/st2000.h b/gcc/config/m68k/st2000.h new file mode 100755 index 0000000..3aea439 --- /dev/null +++ b/gcc/config/m68k/st2000.h @@ -0,0 +1,610 @@ +/* Definitions of target machine for GNU compiler. + Tandem ST-2000 version + Copyright 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + Contributed by Steve Chamberlain + sac@cygnus.com + */ + + + +/* This controls conditionals in m68k.h. */ +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS_NO_LI /* Suppress jump table label usage */ + +#include "aoutos.h" +#undef ASM_OUTPUT_LABELREF +#include "m68k/m68k.h" + + +#undef TARGET_SWITCHES +#undef USER_LABEL_PREFIX +#undef ASM_OUTPUT_LABEL +#undef ASM_GLOBALIZE_LABEL +#undef ASM_OUTPUT_INTERNAL_LABEL +#undef ASM_OUTPUT_DOUBLE +#undef ASM_OUTPUT_FLOAT +#undef ASM_OUTPUT_INT +#undef ASM_OUTPUT_SHORT +#undef ASM_OUTPUT_CHAR +#undef ASM_OUTPUT_BYTE +#undef ASM_OUTPUT_REG_PUSH +#undef ASM_OUTPUT_REG_POP +#undef ASM_OUTPUT_ADDR_VEC_ELT +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#undef ASM_OUTPUT_ALIGN +#undef ASM_OUTPUT_SKIP +#undef ASM_OUTPUT_COMMON +#undef ASM_OUTPUT_LOCAL +#undef ASM_FORMAT_PRIVATE_NAME +#undef TEXT_SECTION_ASM_OP +#undef DATA_SECTION_ASM_OP +#undef ASM_FILE_START +#undef FUNCTION_PROLOGUE +#undef FUNCTION_EPILOGUE +#undef ASM_OUTPUT_LABELREF +#undef REGISTER_NAMES +#undef PRINT_OPERAND +#undef PRINT_OPERAND_ADDRESS +#undef ASM_OUTPUT_ALIGN + +/* See m68k.h. 7 means 68020 with 68881. */ + +#define TARGET_SWITCHES \ + { { "68020", 5}, \ + { "c68020", 5}, \ + { "68881", 2}, \ + { "bitfield", 4}, \ + { "68000", -5}, \ + { "c68000", -5}, \ + { "soft-float", -0102}, \ + { "nobitfield", -4}, \ + { "rtd", 8}, \ + { "nortd", -8}, \ + { "short", 040}, \ + { "noshort", -040}, \ + { "fpa", 0100}, \ + { "nofpa", -0100}, \ + { "sky", 0200}, \ + { "nosky", -0200}, \ + { "68040", 0407}, \ + { "68030", -01400}, \ + { "68030", 7}, \ + { "68040-only", 01000}, \ + { "no-prefix", 02000}, \ + { "", TARGET_DEFAULT}} + +#define TARGET_DEFAULT 7 + +#define USER_LABEL_PREFIX (target_flags & 02000) ? "" : "_" + +/* Define __HAVE_68881__ in preprocessor, unless -msoft-float is specified. + This will control the use of inline 68881 insns in certain macros. */ + +#define CPP_SPEC "%{!msoft-float:-D__HAVE_68881__}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* These are the ones defined by Sony, plus mc68000 for uniformity with + GCC on other 68000 systems. */ + +#define CPP_PREDEFINES "-Dunix -Dbsd43 -Dsony -Dsony_news -Dmc68000 -Dmc68020 -Dnews700" + +/* These conditionals tested for different submodels, + but they were incorrect since they tested the host rather than the target. + The choice of model shouldn't actually matter. */ + + +/* Link with libg.a when debugging, for dbx's sake. */ + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} " + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Override parts of m68k.h to fit Sony's assembler syntax. */ + +#undef BIGGEST_ALIGNMENT +#undef CALL_USED_REGISTERS +#undef FUNCTION_VALUE +#undef LIBCALL_VALUE +#undef FUNCTION_PROFILER + + +#undef ASM_OUTPUT_ALIGN + +/* There is no point aligning anything to a rounder boundary than this. */ +#define BIGGEST_ALIGNMENT 32 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* NEWS makes d2, d3, fp2 and fp3 unsaved registers, unlike the Sun system. */ + +#define CALL_USED_REGISTERS \ + {1, 1, 1, 1, 0, 0, 0, 0, \ + 1, 1, 0, 0, 0, 0, 0, 1, \ + 1, 1, 1, 1, 0, 0, 0, 0} + +/* NEWS returns floats and doubles in fp0, not d0/d1. */ + +#define FUNCTION_VALUE(VALTYPE,FUNC) LIBCALL_VALUE (TYPE_MODE (VALTYPE)) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx (REG, (MODE), ((TARGET_68881 && ((MODE) == SFmode || (MODE) == DFmode)) ? 16 : 0)) + + + + +/* Don't try to define `gcc_compiled.' since the assembler does not + accept symbols with periods. This is no real loss since GDB only + really needs it for parms passed in registers. */ +#define ASM_IDENTIFY_GCC(FILE) + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask = 0; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + if (frame_pointer_needed) \ + { if (fsize < 0x8000) \ + fprintf (FILE, "\tlink fp,#%d\n", -fsize); \ + else if (TARGET_68020) \ + fprintf (FILE, "\tlink.l fp,#%d\n", -fsize); \ + else \ + fprintf (FILE, "\tlink fp,#0\n\tsub.l #%d,sp\n", fsize); } \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (regno - 16); \ + if (mask != 0) \ + fprintf (FILE, "\tfmovem.x #0x%x,-(sp)\n", mask & 0xff); \ + mask = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + mask |= 1 << (15 - regno); \ + if (frame_pointer_needed) \ + mask &= ~ (1 << (15-FRAME_POINTER_REGNUM)); \ + if (exact_log2 (mask) >= 0) \ + fprintf (FILE, "\tmove.l %s,-(sp)\n", reg_names[15 - exact_log2 (mask)]); \ + else if (mask) fprintf (FILE, "\tmovem.l #0x%x,-(sp)\n", mask); } + +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmove.l #LP%d,d0\n\tjsr mcount\n", (LABEL_NO)); + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ +{ register int regno; \ + register int mask, fmask; \ + register int nregs; \ + int offset, foffset; \ + extern char call_used_regs[]; \ + int fsize = ((SIZE) + 3) & -4; \ + int big = 0; \ + nregs = 0; fmask = 0; \ + for (regno = 16; regno < FIRST_PSEUDO_REGISTER; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; fmask |= 1 << (23 - regno); } \ + foffset = nregs * 12; \ + nregs = 0; mask = 0; \ + if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0; \ + for (regno = 0; regno < 16; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + { nregs++; mask |= 1 << regno; } \ + offset = foffset + nregs * 4; \ + if (offset + fsize >= 0x8000 \ + && frame_pointer_needed \ + && (mask || fmask)) \ + { fprintf (FILE, "\tmove.l #%d,a0\n", -fsize); \ + fsize = 0, big = 1; } \ + if (exact_log2 (mask) >= 0) { \ + if (big) \ + fprintf (FILE, "\tmove.l (-%d,fp,a0.l),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmove.l (sp)+,%s\n", \ + reg_names[exact_log2 (mask)]); \ + else \ + fprintf (FILE, "\tmove.l (-%d,fp),%s\n", \ + offset + fsize, reg_names[exact_log2 (mask)]); } \ + else if (mask) { \ + if (big) \ + fprintf (FILE, "\tmovem.l (-%d,fp,a0.l),#0x%x\n", \ + offset + fsize, mask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tmovem.l (sp)+,#0x%x\n", mask); \ + else \ + fprintf (FILE, "\tmovem.l (-%d,fp),#0x%x\n", \ + offset + fsize, mask); } \ + if (fmask) { \ + if (big) \ + fprintf (FILE, "\tfmovem.x (-%d,fp,a0.l),#0x%x\n", \ + foffset + fsize, fmask); \ + else if (! frame_pointer_needed) \ + fprintf (FILE, "\tfmovem.x (sp)+,#0x%x\n", fmask); \ + else \ + fprintf (FILE, "\tfmovem.x (-%d,fp),#0x%x\n", \ + foffset + fsize, fmask); } \ + if (frame_pointer_needed) \ + fprintf (FILE, "\tunlk fp\n"); \ + if (current_function_pops_args) \ + fprintf (FILE, "\trtd #%d\n", current_function_pops_args); \ + else fprintf (FILE, "\trts\n"); } + +/* Difference from m68k.h is in `fp' instead of `a6'. */ + +#define REGISTER_NAMES \ +{"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7"} + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmove.l\t%s,-(sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmove.l\t(sp)+,%s\n", reg_names[REGNO]) + + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + + +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "#"); \ + else if (CODE == '-') fprintf (FILE, "-(sp)"); \ + else if (CODE == '+') fprintf (FILE, "(sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(sp)"); \ + else if (CODE == '!') fprintf (FILE, "ccr"); \ + else if (CODE == '$') {if (TARGET_68040_ONLY) fprintf (FILE, "s");} \ + else if (CODE == '&') {if (TARGET_68040_ONLY) fprintf (FILE, "d");} \ + 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 if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { union { double d; int i[2]; } u; \ + union { float f; int i; } u1; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + u1.f = u.d; \ + if (CODE == 'f') \ + fprintf (FILE, "#0f%.9e", u1.f); \ + else \ + fprintf (FILE, "#0x%x", u1.i); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != DImode) \ + { union { double d; int i[2]; } u; \ + u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \ + fprintf (FILE, "#0d%.20e", u.d); } \ + else if (CODE == 'b') { putc('#', FILE); output_addr_const (FILE, X);}\ + else { putc ('#', FILE); output_addr_const (FILE, X); }} + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "(L%d.b,pc,%s.w", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (breg)]); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr && GET_CODE (addr) == LABEL_REF) abort (); \ + fprintf (FILE, "("); \ + if (addr != 0) { \ + output_addr_const (FILE, addr); \ + putc (',', FILE); } \ + fprintf (FILE, "%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "(L%d.b,pc,%s.l)", \ + CODE_LABEL_NUMBER (XEXP (addr, 0)), \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + if (GET_CODE (addr) == CONST_INT \ + && INTVAL (addr) < 0x8000 \ + && INTVAL (addr) >= -0x8000) \ + fprintf (FILE, "%d.w", INTVAL (addr)); \ + else \ + output_addr_const (FILE, addr); \ + }} + + + +/* This is how to output the definition of a user-level label named NAME, + such as the label on a static function or variable NAME. */ + +#define ASM_OUTPUT_LABEL(FILE,NAME) \ + do { assemble_name (FILE, NAME); fputs ("\n", FILE); } while (0) + +/* This is how to output a command to make the user-level label named NAME + defined for reference from other files. */ + +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + do { fputs ("\tXDEF\t", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + asm_fprintf (FILE, "%U%s", NAME) + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + asm_fprintf (FILE, "%s%d\n", PREFIX, NUM) + +/* This is how to store into the string LABEL + the symbol_ref name of an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. + This is suitable for output with `assemble_name'. */ + + +#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ + sprintf (LABEL, "*%s%s%d", LOCAL_LABEL_PREFIX, PREFIX, NUM) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + fprintf (FILE, "\tDC.D\t0r%.20g\n", (VALUE)) + +/* This is how to output an assembler line defining a `float' constant. */ + +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + fprintf (FILE, "\tDC.S\t0r%.20g\n", (VALUE)) + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tDC.L\t"), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tDC.W\t"), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tDC.B\t"), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tDC.B\t0x%x\n", (VALUE)) + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + + +/* This is how to output an element of a case-vector that is absolute. + (The 68000 does not use such vectors, + but we must define this macro anyway.) */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + asm_fprintf (FILE, "\tDC.L\t%LL%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\tDC.W\t%LL%d-%LL%d\n", VALUE, REL) + +/* This is how to output an assembler line + that says to advance the location counter + to a multiple of 2**LOG bytes. */ + +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + fprintf (FILE, "\tALIGN\t%d\n", 1<<LOG); + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tDS.B\t%u\n", (SIZE)) + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tXCOM\t", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%u\n", (ROUNDED))) + +/* This says how to output an assembler line + to define a local common symbol. */ + +/* There doesn't seem to be a way to say this in MRI way */ +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( data_section(), assemble_name ((FILE), (NAME)), fputs ("\n\tDS.B ", (FILE)), \ + fprintf ((FILE), "%u\n", (ROUNDED))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s__%d", (NAME), (LABELNO))) + +#define TEXT_SECTION_ASM_OP "\tSECT\t.text" +#define DATA_SECTION_ASM_OP "\tSECT\t.data" +#define BSS_SECTION_ASM_OP "\tSECT\t.bss" + +#define MAX_TEXT_ALIGN 32 + +#define ASM_FILE_START(FILE) \ + fprintf (FILE, "* TANDEM ST-2000 M68K GCC\n"); \ + fprintf (FILE, "* Cygnus Support (415) 322-3811\n"); \ + fprintf (FILE, "* bugs@cygnus.com\n\n"); + + +#define SECTION_ASM_OP "\tSECT\t" + +#define EXTRA_SECTIONS in_user + +#undef SELECT_SECTION + +#define SELECT_SECTION(DECL,RELOC) \ +do { \ + if (TREE_CODE (DECL) == VAR_DECL || TREE_CODE (DECL) == FUNCTION_DECL)\ + { \ + if (GET_CODE (DECL_RTL (DECL)) == MEM \ + && GET_CODE (XEXP (DECL_RTL (DECL), 0)) == SYMBOL_REF \ + && SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0))) \ + { \ + rtx sym = XEXP (DECL_RTL (DECL), 0); \ + int len = (char *) index (XEXP (sym, 0), ' ') - XSTR (sym, 0); \ + char *section_name = (char *)alloca (len+1); \ + strncpy (section_name, XEXP (sym, 0), len); \ + section_name[len] = '\0'; \ + in_section = in_user; \ + fprintf (asm_out_file, "\tSECT\t%s\n", section_name); \ + break; \ + } \ + } \ + if (TREE_CODE (DECL) == VAR_DECL) \ + { \ + if (TREE_READONLY (DECL) && ! TREE_SIDE_EFFECTS (DECL) \ + && DECL_ALIGN (DECL) <= MAX_TEXT_ALIGN \ + && ! (flag_pic && RELOC)) \ + text_section (); \ + else \ + data_section (); \ + } \ + else if (TREE_CODE (DECL) == CONSTRUCTOR) \ + { \ + if (flag_pic != 0 && RELOC != 0) \ + data_section (); \ + else \ + text_section (); \ + } \ + else if (*tree_code_type[(int) TREE_CODE (DECL)] == 'c') \ + { \ + if ((TREE_CODE (DECL) == STRING_CST && flag_writable_strings) \ + || TYPE_ALIGN (TREE_TYPE (DECL)) > MAX_TEXT_ALIGN) \ + data_section (); \ + else \ + text_section (); \ + } \ + else text_section() ;\ +} while (0) diff --git a/gcc/config/m68k/sun2.h b/gcc/config/m68k/sun2.h new file mode 100755 index 0000000..679e57a --- /dev/null +++ b/gcc/config/m68k/sun2.h @@ -0,0 +1,77 @@ +/* Definitions of target machine for GNU compiler. Sun 68010 version. + Copyright (C) 1987, 1988, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "m68k/m68k.h" + +/* See m68k.h. 0 means 68000 with no 68881. */ + +#define TARGET_DEFAULT 0 + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#define CPP_SPEC "%{m68881:-D__HAVE_68881__} \ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +/* -m68020 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68020:-mc68020}%{mc68020:-mc68020}%{!mc68020:%{!m68020:-mc68010}} \ + %{fpic:-k} %{fPIC:-k} %{R} %{j} %{J} %{h} %{d2} %{keep-local-as-symbols:-L}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* Prevent error on `-sun2' and `-target sun2' options. */ + +#define CC1_SPEC "%{sun2:} %{target:}" + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) \ + (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \ + || !strcmp (STR, "target") || !strcmp (STR, "assert")) + +/* Specify what to link with. */ + +/* Link with libg.a when debugging, for dbx's sake. */ +/* Include the support for -a when appropriate. */ +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} " + +/* Alignment of field after `int : 0' in a structure. */ + +#undef EMPTY_FIELD_BOUNDARY +#define EMPTY_FIELD_BOUNDARY 16 + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO diff --git a/gcc/config/m68k/sun2o4.h b/gcc/config/m68k/sun2o4.h new file mode 100755 index 0000000..da722cf --- /dev/null +++ b/gcc/config/m68k/sun2o4.h @@ -0,0 +1,189 @@ +/* Definitions of target machine for GNU compiler. Sun 2 running SunOS 4. + Copyright (C) 1987, 1988, 1993, 1996, 1997 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 "m68k/sun2.h" + + +/* Define __HAVE_SKY__ in preprocessor, according to the -m flags. + Also inform the program which CPU this is for. */ + +#undef CPP_SPEC + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" +#undef SIZE_TYPE +#define SIZE_TYPE "int" +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +#if TARGET_DEFAULT & MASK_SKY + +/* -msky is the default */ +#define CPP_SPEC \ +"%{!msoft-float:-D__HAVE_SKY__}\ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{msky:-D__HAVE_SKY__ }\ +%{!ansi:%{m68020:-Dmc68020}%{mc68020:-Dmc68020}%{!mc68020:%{!m68020:-Dmc68010}}}" + +#endif + +/* STARTFILE_SPEC to include sun floating point initialization + This is necessary (tr: Sun does it) for the sky routines. + I'm not sure what would happen below if people gave contradictory + arguments (eg. -msoft-float -mfpa) */ + +#undef STARTFILE_SPEC + +#if TARGET_DEFAULT & MASK_SKY +/* -msky is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{msoft-float:Fcrt1.o%s} \ + %{!msoft-float:Scrt1.o%s}" +#else +/* -msoft-float is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{msky:Scrt1.o%s} \ + %{!msky:Fcrt1.o%s}" +#endif + +/* Specify library to handle `-a' basic block profiling. + Control choice of libm.a (if user says -lm) + based on fp arith default and options. */ + +#undef LIB_SPEC + +#if TARGET_DEFAULT & MASK_SKY +/* -msky is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft} \ +%{!msoft_float:-L/usr/lib/fsky}" +#else +/* -msoft-float is the default */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{a:/usr/lib/bb_link.o -lc} %{g:-lg} \ +%{!msky:-L/usr/lib/fsoft} \ +%{msky:-L/usr/lib/ffpa}" +#endif + +#undef LINK_SPEC +#define LINK_SPEC \ + "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic}" + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.double 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.double 0r99e999\n"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + fprintf (FILE, "\t.long 0x80000000,0\n"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } \ + } while (0) + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.single 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.single 0r99e999\n"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + fprintf (FILE, "\t.long 0x80000000\n"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", dstr); \ + fprintf (FILE, "\t.single 0r%s\n", dstr); \ + } \ + } while (0) + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE != 'f') \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I0x%x", l); \ + else \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + else if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + fprintf (FILE, "#0r-0.0"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.9g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "#0r-99e999"); \ + else \ + fprintf (FILE, "#0r99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + fprintf (FILE, "#0r-0.0"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.20g", dstr); \ + fprintf (FILE, "#0r%s", dstr); \ + } \ + } while (0) diff --git a/gcc/config/m68k/sun3.h b/gcc/config/m68k/sun3.h new file mode 100755 index 0000000..13e927e --- /dev/null +++ b/gcc/config/m68k/sun3.h @@ -0,0 +1,301 @@ +/* Definitions of target machine for GNU compiler. Sun 68000/68020 version. + Copyright (C) 1987, 1988, 1993, 1995, 1996 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. */ + +/* This comment is here to see if it will keep Sun's cpp from dying. */ + +/* If you do not need to generate floating point code for the optional + Sun FPA board, you can safely comment out the SUPPORT_SUN_FPA define + to gain a little speed and code size. */ + +#define SUPPORT_SUN_FPA + +#include "m68k/m68k.h" + +/* See m68k.h. 7 means 68020 with 68881. */ + +#ifndef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68881|MASK_68020) +#endif + +/* Define __HAVE_FPA__ or __HAVE_68881__ in preprocessor, + according to the -m flags. + This will control the use of inline 68881 insns in certain macros. + Also inform the program which CPU this is for. */ + +#if TARGET_DEFAULT & MASK_68881 + +/* -m68881 is the default */ +#define CPP_SPEC \ +"%{!msoft-float:%{mfpa:-D__HAVE_FPA__ }%{!mfpa:-D__HAVE_68881__ }}\ +%{m68000:-D__mc68010__}%{mc68000:-D__mc68010__}%{!mc68000:%{!m68000:-D__mc68020__}} \ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#else + +/* -msoft-float is the default */ +#define CPP_SPEC \ +"%{m68881:-D__HAVE_68881__ }%{mfpa:-D__HAVE_FPA__ }\ +%{m68000:-D__mc68010__}%{mc68000:-D__mc68010__}%{!mc68000:%{!m68000:-D__mc68020__}} \ +%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{!mc68000:%{!m68000:-Dmc68020}}}" + +#endif + +/* Prevent error on `-sun3' and `-target sun3' options. */ + +#define CC1_SPEC "%{sun3:} %{target:}" + +#define PTRDIFF_TYPE "int" + +/* We must override m68k.h. */ +#undef WCHAR_TYPE +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE "short unsigned int" +#define WCHAR_TYPE_SIZE 16 + +/* These compiler options take an argument. We ignore -target for now. */ + +#define WORD_SWITCH_TAKES_ARG(STR) \ + (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \ + || !strcmp (STR, "target") || !strcmp (STR, "assert")) + +/* -m68000 requires special flags to the assembler. */ + +#define ASM_SPEC \ + "%{m68000:-mc68010}%{mc68000:-mc68010}%{!mc68000:%{!m68000:-mc68020}} \ + %{fpic:-k} %{fPIC:-k} %{R} %{j} %{J} %{h} %{d2} %{keep-local-as-symbols:-L}" + +/* Names to predefine in the preprocessor for this target machine. */ +/* For a while, -D_CROSS_TARGET_ARCH=SUN3 was included here, + but it doesn't work, partly because SUN3 etc. aren't defined + (and shouldn't be). It seems that on a native compiler _CROSS_TARGET_ARCH + should not be defined. For cross compilers, let's do things as we + normally do in GCC. -- rms. */ + +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Asystem(unix) -Asystem(bsd) -Acpu(m68k) -Amachine(m68k)" + +/* STARTFILE_SPEC to include sun floating point initialization + This is necessary (tr: Sun does it) for both the m68881 and the fpa + routines. + Note that includes knowledge of the default specs for gcc, ie. no + args translates to the same effect as -m68881 + I'm not sure what would happen below if people gave contradictory + arguments (eg. -msoft-float -mfpa) */ + +#if TARGET_DEFAULT & MASK_FPA +/* -mfpa is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!m68881:%{!msoft-float:Wcrt1.o%s}}" +#else +#if TARGET_DEFAULT & MASK_68881 +/* -m68881 is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{mfpa:Wcrt1.o%s} \ + %{msoft-float:Fcrt1.o%s} \ + %{!mfpa:%{!msoft-float:Mcrt1.o%s}}" +#else +/* -msoft-float is the default */ +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}} \ + %{m68881:Mcrt1.o%s} \ + %{mfpa:Wcrt1.o%s} \ + %{!m68881:%{!mfpa:Fcrt1.o%s}}" +#endif +#endif + +/* Specify library to handle `-a' basic block profiling. + Control choice of libm.a (if user says -lm) + based on fp arith default and options. */ + +#if TARGET_DEFAULT & MASK_FPA +/* -mfpa is the default */ +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{m68881:-L/usr/lib/f68881}\ +%{!msoft_float:%{!m68881:-L/usr/lib/ffpa}}" +#else +#if TARGET_DEFAULT & MASK_68881 +/* -m68881 is the default */ +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{g:-lg} \ +%{msoft-float:-L/usr/lib/fsoft}%{!msoft-float:%{!mfpa:-L/usr/lib/f68881}}\ +%{mfpa:-L/usr/lib/ffpa}" +#else +/* -msoft-float is the default */ +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{g:-lg} \ +%{!m68881:%{!mfpa:-L/usr/lib/fsoft}}%{m68881:-L/usr/lib/f68881}\ +%{mfpa:-L/usr/lib/ffpa}" +#endif +#endif + +/* Provide required defaults for linker -e and -d switches. */ + +#define LINK_SPEC \ + "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*}" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* This is BSD, so it wants DBX format. */ + +#define DBX_DEBUGGING_INFO + +/* Allow folding division by zero. */ +#define REAL_INFINITY + +/* Generate calls to memcpy, memcmp and memset. */ +#define TARGET_MEM_FUNCTIONS + +/* This is not a good idea. It prevents interoperation between + files compiled with -m68881 and those compiled with -msoft-float. */ +#if 0 +#define FUNCTION_VALUEX(MODE) \ + gen_rtx (REG, (MODE), \ + ((TARGET_68881 \ + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode)) \ + ? 16 : 0)) + +#undef FUNCTION_VALUE +#define FUNCTION_VALUE(VALTYPE,FUNC) FUNCTION_VALUEX (TYPE_MODE (VALTYPE)) +#endif /* 0 */ + +/* This is how to output an assembler line defining a `double' constant. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + { \ + if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.double 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.double 0r99e999\n"); \ + } \ + else if (REAL_VALUE_ISNAN (VALUE)) \ + { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), l); \ + fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", l[0], l[1]); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.17g", dstr); \ + fprintf (FILE, "\t.double 0r%s\n", dstr); \ + } \ + } + +/* This is how to output an assembler line defining a `float' constant. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + { \ + if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + fprintf (FILE, "\t.single 0r-99e999\n"); \ + else \ + fprintf (FILE, "\t.single 0r99e999\n"); \ + } \ + else if (REAL_VALUE_ISNAN (VALUE)) \ + { long l; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), l); \ + fprintf (FILE, "\t.long 0x%lx\n", l); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.9g", dstr); \ + fprintf (FILE, "\t.single 0r%s\n", dstr); \ + } \ + } + +/* This is how to output an assembler lines defining floating operands. + There's no way to output a NaN's fraction, so we lose it. */ + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { \ + if (CODE != 'f') \ + { \ + long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + if (sizeof (int) == sizeof (long)) \ + asm_fprintf ((FILE), "%I0x%x", l); \ + else \ + asm_fprintf ((FILE), "%I0x%lx", l); \ + } \ + else if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + asm_fprintf (FILE, "%I0r-99e999"); \ + else \ + asm_fprintf (FILE, "%I0r99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + asm_fprintf (FILE, "%I0r-0.0"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.9g", dstr); \ + asm_fprintf (FILE, "%I0r%s", dstr); \ + } \ + } while (0) + +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { if (REAL_VALUE_ISINF (VALUE)) \ + { \ + if (REAL_VALUE_NEGATIVE (VALUE)) \ + asm_fprintf (FILE, "%I0r-99e999"); \ + else \ + asm_fprintf (FILE, "%I0r99e999"); \ + } \ + else if (REAL_VALUE_MINUS_ZERO (VALUE)) \ + { \ + asm_fprintf (FILE, "%I0r-0.0"); \ + } \ + else \ + { char dstr[30]; \ + REAL_VALUE_TO_DECIMAL ((VALUE), "%.17g", dstr); \ + asm_fprintf (FILE, "%I0r%s", dstr); \ + } \ + } while (0) + +#if 0 +/* This was turned off as it caused linking errors on sunos4.1. + `gcc -a' links in /usr/lib/bb_link.o which does not provide __bb_link + but its own version of __bb_init_func. */ +#undef BLOCK_PROFILER_CODE +#define BLOCK_PROFILER_CODE \ +extern int ___tcov_init; \ + \ +__bb_init_func (blocks) \ + struct bb *blocks; \ +{ \ + if (! ___tcov_init) \ + ___tcov_init_func (); \ + \ + ___bb_link (blocks->filename, blocks->counts, blocks->ncounts); \ +} +#endif diff --git a/gcc/config/m68k/sun3mach.h b/gcc/config/m68k/sun3mach.h new file mode 100755 index 0000000..1c76cc4 --- /dev/null +++ b/gcc/config/m68k/sun3mach.h @@ -0,0 +1,15 @@ +#include "m68k/sun3.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -Dsun -Dsun3 -Dunix -DMACH -DCMU -DMTXINU -DBIT_MSF -DBYTE_MSF -Asystem(unix) -Asystem(mach) -Acpu(m68k) -Amachine(m68k)" + +/* Specify extra dir to search for include files. */ +#define SYSTEM_INCLUDE_DIR "/usr/mach/include" + +/* LINK_SPEC is needed only for SunOS 4. */ + +#undef LINK_SPEC + +/* Don't default to pcc-struct-return, because gcc is the only compiler, and + we want to retain compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 diff --git a/gcc/config/m68k/sun3n.h b/gcc/config/m68k/sun3n.h new file mode 100755 index 0000000..32f5f65 --- /dev/null +++ b/gcc/config/m68k/sun3n.h @@ -0,0 +1,9 @@ +/* Define target machine as a Sun 3 with no 68881. */ + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +#include "m68k/sun3.h" + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 diff --git a/gcc/config/m68k/sun3n3.h b/gcc/config/m68k/sun3n3.h new file mode 100755 index 0000000..38680d8 --- /dev/null +++ b/gcc/config/m68k/sun3n3.h @@ -0,0 +1,5 @@ +#include "m68k/sun3n.h" + +/* LINK_SPEC is needed only for SunOS 4. */ + +#undef LINK_SPEC diff --git a/gcc/config/m68k/sun3o3.h b/gcc/config/m68k/sun3o3.h new file mode 100755 index 0000000..95f1ff6 --- /dev/null +++ b/gcc/config/m68k/sun3o3.h @@ -0,0 +1,5 @@ +#include "m68k/sun3.h" + +/* LINK_SPEC is needed only for SunOS 4. */ + +#undef LINK_SPEC diff --git a/gcc/config/m68k/t-adobe b/gcc/config/m68k/t-adobe new file mode 100755 index 0000000..c46960c --- /dev/null +++ b/gcc/config/m68k/t-adobe @@ -0,0 +1,9 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sun3.asm + +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _divdf3 _muldf3 _negdf2 _adddf3 _subdf3 \ + _fixdfsi _fixsfsi _floatsidf _floatsisf _truncdfsf2 _extendsfdf2 \ + _addsf3 _negsf2 _subsf3 _mulsf3 _divsf3 \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 diff --git a/gcc/config/m68k/t-aux b/gcc/config/m68k/t-aux new file mode 100755 index 0000000..3d59d67 --- /dev/null +++ b/gcc/config/m68k/t-aux @@ -0,0 +1,44 @@ +# Makefile additions for A/UX + +LIB2FUNCS_EXTRA=aux-mcount.c aux-exit.c + +FIXPROTO_DEFINES=-D_POSIX_SOURCE + +# Only really needed for collect2 +CLIB=-lld + +# Needed to support builds for multiple versions of A/UX +# LDFLAGS=-static + +# Make sure we get the right assembler by letting gcc choose +AS = $(GCC_FOR_TARGET) -xassembler-with-cpp -D__ASSEMBLY__ $(INCLUDES) -c + +aux-mcount.c: $(srcdir)/config/m68k/aux-mcount.c + cp $(srcdir)/config/m68k/aux-mcount.c aux-mcount.c + +aux-exit.c: $(srcdir)/config/m68k/aux-exit.c + cp $(srcdir)/config/m68k/aux-exit.c aux-exit.c + +crt1.o: $(srcdir)/config/m68k/aux-crt1.c $(GCC_PASSES) + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -o crt1.o -c \ + -fno-omit-frame-pointer $(srcdir)/config/m68k/aux-crt1.c + +mcrt1.o: $(srcdir)/config/m68k/aux-crt1.c $(GCC_PASSES) + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -o mcrt1.o -c \ + -fno-omit-frame-pointer -DMCRT1 $(srcdir)/config/m68k/aux-crt1.c + +maccrt1.o: $(srcdir)/config/m68k/aux-crt1.c $(GCC_PASSES) + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -o maccrt1.o -c \ + -fno-omit-frame-pointer -DMACCRT1 $(srcdir)/config/m68k/aux-crt1.c + +crt2.o: $(srcdir)/config/m68k/aux-crt2.asm $(GCC_PASSES) + $(AS) -o crt2.o $(srcdir)/config/m68k/aux-crt2.asm + +crtn.o: $(srcdir)/config/m68k/aux-crtn.asm $(GCC_PASSES) + $(AS) -o crtn.o $(srcdir)/config/m68k/aux-crtn.asm + +low.gld: $(srcdir)/config/m68k/aux-low.gld + sed -e 's|@libdir@|$(libdir)|' -e 's|@tooldir@|$(tooldir)|' \ + -e 's|@local_prefix@|$(local_prefix)|' \ + $(srcdir)/config/m68k/aux-low.gld > tmp-low.gld + mv tmp-low.gld low.gld diff --git a/gcc/config/m68k/t-linux b/gcc/config/m68k/t-linux new file mode 100755 index 0000000..99dc452 --- /dev/null +++ b/gcc/config/m68k/t-linux @@ -0,0 +1,2 @@ +# On GNU/Linux we can print long double +ENQUIRE_CFLAGS = -DNO_MEM -O0 diff --git a/gcc/config/m68k/t-linux-aout b/gcc/config/m68k/t-linux-aout new file mode 100755 index 0000000..99dc452 --- /dev/null +++ b/gcc/config/m68k/t-linux-aout @@ -0,0 +1,2 @@ +# On GNU/Linux we can print long double +ENQUIRE_CFLAGS = -DNO_MEM -O0 diff --git a/gcc/config/m68k/t-lynx b/gcc/config/m68k/t-lynx new file mode 100755 index 0000000..6f2caba --- /dev/null +++ b/gcc/config/m68k/t-lynx @@ -0,0 +1,6 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sf68.asm +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _double _float _floatex \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 diff --git a/gcc/config/m68k/t-m68kbare b/gcc/config/m68k/t-m68kbare new file mode 100755 index 0000000..d334eab --- /dev/null +++ b/gcc/config/m68k/t-m68kbare @@ -0,0 +1,24 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sf68.asm +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _double _float _floatex \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... +LIB2FUNCS_EXTRA = fpgnulib.c xfgnulib.c + +fpgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + cp $(srcdir)/config/m68k/fpgnulib.c fpgnulib.c +xfgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + echo '#define EXTFLOAT' > xfgnulib.c + cat $(srcdir)/config/m68k/fpgnulib.c >> xfgnulib.c + +MULTILIB_OPTIONS = m68000/m68020/m5200/mcpu32 m68881/msoft-float +MULTILIB_DIRNAMES = +MULTILIB_MATCHES = m68000=mc68000 m68000=m68302 mcpu32=m68332 m68020=mc68020 m68020=m68040 m68020=m68060 +MULTILIB_EXCEPTIONS = m68000/msoft-float m5200/m68881 m5200/msoft-float mcpu32/m68881 mcpu32/msoft-float + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/m68k/t-m68kelf b/gcc/config/m68k/t-m68kelf new file mode 100755 index 0000000..d0f857a --- /dev/null +++ b/gcc/config/m68k/t-m68kelf @@ -0,0 +1,29 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sf68.asm +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _double _float _floatex \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... +LIB2FUNCS_EXTRA = fpgnulib.c xfgnulib.c + +fpgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + cp $(srcdir)/config/m68k/fpgnulib.c fpgnulib.c +xfgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + echo '#define EXTFLOAT' > xfgnulib.c + cat $(srcdir)/config/m68k/fpgnulib.c >> xfgnulib.c + +MULTILIB_OPTIONS = m68000/m68020/m5200/mcpu32 m68881/msoft-float +MULTILIB_DIRNAMES = +MULTILIB_MATCHES = m68000=mc68000 m68000=m68302 mcpu32=m68332 m68020=mc68020 m68020=m68040 m68020=m68060 +MULTILIB_EXCEPTIONS = m68000/msoft-float m5200/m68881 m5200/msoft-float mcpu32/m68881 mcpu32/msoft-float + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +# from ../t-svr4 +EXTRA_PARTS=crtbegin.o crtend.o +# no pic for now +#CRTSTUFF_T_CFLAGS=-fpic diff --git a/gcc/config/m68k/t-mot3300 b/gcc/config/m68k/t-mot3300 new file mode 100755 index 0000000..2fc1185 --- /dev/null +++ b/gcc/config/m68k/t-mot3300 @@ -0,0 +1,10 @@ +MULTILIB_OPTIONS=m68000/m68020 msoft-float +MULTILIB_DIRNAMES= +MULTILIB_MATCHES=m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +CRT0_S = $(srcdir)/config/m68k/mot3300-crt0.S +MCRT0_S = $(srcdir)/config/m68k/mot3300Mcrt0.S +CRT0STUFF_T_CFLAGS = -DMOTOROLA -DSGS_CMP_ORDER diff --git a/gcc/config/m68k/t-mot3300-gald b/gcc/config/m68k/t-mot3300-gald new file mode 100755 index 0000000..435afc4 --- /dev/null +++ b/gcc/config/m68k/t-mot3300-gald @@ -0,0 +1,13 @@ +T_CPPFLAGS = -DUSE_GAS -DUSE_GLD +TARGET_LIBGCC2_CFLAGS = -DUSE_GAS + +MULTILIB_OPTIONS=m68000/m68020 msoft-float +MULTILIB_DIRNAMES= +MULTILIB_MATCHES=m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +CRT0_S = $(srcdir)/config/m68k/mot3300-crt0.S +MCRT0_S = $(srcdir)/config/m68k/mot3300Mcrt0.S +CRT0STUFF_T_CFLAGS = diff --git a/gcc/config/m68k/t-mot3300-gas b/gcc/config/m68k/t-mot3300-gas new file mode 100755 index 0000000..5256674 --- /dev/null +++ b/gcc/config/m68k/t-mot3300-gas @@ -0,0 +1,13 @@ +T_CPPFLAGS = -DUSE_GAS +TARGET_LIBGCC2_CFLAGS = -DUSE_GAS + +MULTILIB_OPTIONS=m68000/m68020 msoft-float +MULTILIB_DIRNAMES= +MULTILIB_MATCHES=m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +CRT0_S = $(srcdir)/config/m68k/mot3300-crt0.S +MCRT0_S = $(srcdir)/config/m68k/mot3300Mcrt0.S +CRT0STUFF_T_CFLAGS = diff --git a/gcc/config/m68k/t-mot3300-gld b/gcc/config/m68k/t-mot3300-gld new file mode 100755 index 0000000..8cc3ed6 --- /dev/null +++ b/gcc/config/m68k/t-mot3300-gld @@ -0,0 +1,12 @@ +T_CPPFLAGS = -DUSE_GLD + +MULTILIB_OPTIONS=m68000/m68020 msoft-float +MULTILIB_DIRNAMES= +MULTILIB_MATCHES=m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +CRT0_S = $(srcdir)/config/m68k/mot3300-crt0.S +MCRT0_S = $(srcdir)/config/m68k/mot3300Mcrt0.S +CRT0STUFF_T_CFLAGS = -DMOTOROLA -DSGS_CMP_ORDER diff --git a/gcc/config/m68k/t-next b/gcc/config/m68k/t-next new file mode 100755 index 0000000..787ee79 --- /dev/null +++ b/gcc/config/m68k/t-next @@ -0,0 +1,6 @@ +# libgcc1.c is not needed, since the standard library has these functions. +LIBGCC1= +CROSS_LIBGCC1= + +nextstep.o: $(srcdir)/config/nextstep.c $(CONFIG_H) flags.h tree.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< diff --git a/gcc/config/m68k/t-ose68 b/gcc/config/m68k/t-ose68 new file mode 100755 index 0000000..5f9cba2 --- /dev/null +++ b/gcc/config/m68k/t-ose68 @@ -0,0 +1,26 @@ +# CYGNUS LOCAL ericsson + +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sf68.asm +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _double _float _floatex \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... +LIB2FUNCS_EXTRA = fpgnulib.c xfgnulib.c + +fpgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + cp $(srcdir)/config/m68k/fpgnulib.c fpgnulib.c +xfgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + echo '#define EXTFLOAT' > xfgnulib.c + cat $(srcdir)/config/m68k/fpgnulib.c >> xfgnulib.c + +MULTILIB_OPTIONS= m68000/m68020 m68881/msoft-float +MULTILIB_DIRNAMES = +MULTILIB_MATCHES = m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + diff --git a/gcc/config/m68k/t-vxworks68 b/gcc/config/m68k/t-vxworks68 new file mode 100755 index 0000000..7fa5943 --- /dev/null +++ b/gcc/config/m68k/t-vxworks68 @@ -0,0 +1,27 @@ +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = m68k/lb1sf68.asm +LIB1ASMFUNCS = _mulsi3 _udivsi3 _divsi3 _umodsi3 _modsi3 \ + _double _float _floatex \ + _eqdf2 _nedf2 _gtdf2 _gedf2 _ltdf2 _ledf2 \ + _eqsf2 _nesf2 _gtsf2 _gesf2 _ltsf2 _lesf2 + +# We don't want to put exit in libgcc.a for VxWorks, because VxWorks +# does not have _exit. +TARGET_LIBGCC2_CFLAGS = -Dexit=unused_exit + +# These are really part of libgcc1, but this will cause them to be +# built correctly, so... +LIB2FUNCS_EXTRA = fpgnulib.c xfgnulib.c + +fpgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + cp $(srcdir)/config/m68k/fpgnulib.c fpgnulib.c +xfgnulib.c: $(srcdir)/config/m68k/fpgnulib.c + echo '#define EXTFLOAT' > xfgnulib.c + cat $(srcdir)/config/m68k/fpgnulib.c >> xfgnulib.c + +MULTILIB_OPTIONS = m68000/m68020 m68881/msoft-float +MULTILIB_DIRNAMES = +MULTILIB_MATCHES = m68000=mc68000 m68000=m68302 m68000=m68332 m68020=mc68020 m68020=m68040 + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/m68k/tower-as.h b/gcc/config/m68k/tower-as.h new file mode 100755 index 0000000..7b5771a --- /dev/null +++ b/gcc/config/m68k/tower-as.h @@ -0,0 +1,616 @@ +/* Definitions of target machine for GNU compiler. + For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. + Copyright (C) 1990, 1993, 1994, 1996, 1997 Free Software Foundation, Inc. + Contributed by Robert Andersson (ra@intsys.no), International Systems, + Oslo, Norway. + +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. */ + + +/* This file outputs assembler source suitable for the native Tower as + and with sdb debugging symbols. See tower.h for more comments. + + This file was based on m68k.h, hp320.h and 3b1.h as of the + 1.37.1 version. */ + +#include "m68k/tower.h" +#undef SELECT_RTX_SECTION + +/* Use default settings for system V.3. */ + +#include "svr3.h" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_600 -D__motorola__ -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" + +/* Define __HAVE_68881 in preprocessor only if -m68881 is specified. + This will control the use of inline 68881 insns in certain macros. + Also, define special define used to identify the Tower assembler. */ + +#define CPP_SPEC "-D__TOWER_ASM__ %{m68881:-D__HAVE_68881__}" + +/* We don't want local labels to start with period. + See ASM_OUTPUT_INTERNAL_LABEL. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "" + +/* The prefix to add to user-visible assembler symbols. */ +/* We do not want leading underscores. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* These four macros control how m68k.md is expanded. */ + +#define MOTOROLA /* Use Motorola syntax rather than "MIT" */ +#define SGS /* Uses SGS assembler */ +#define SGS_CMP_ORDER /* Takes cmp operands in reverse order */ +#define SGS_NO_LI /* Suppress jump table label usage */ + +/* Turn on SDB debugging info. */ + +#define SDB_DEBUGGING_INFO + +/* This is only useful if gdb is changed, but doesn't harm anyway. */ + +#define ASM_IDENTIFY_GCC(FILE) \ + fprintf (FILE, "gcc2_compiled%%:\n") + +/* All the ASM_OUTPUT macros need to conform to the Tower as syntax. */ + +#define ASM_OUTPUT_SOURCE_FILENAME(FILE, FILENAME) \ + do { \ + fprintf (FILE, "\tfile\t"); \ + output_quoted_string (FILE, FILENAME); \ + fprintf (FILE, "\n"); \ + fprintf (FILE, "section ~init,\"x\"\n"); \ + fprintf (FILE, "section ~fini,\"x\"\n"); \ + fprintf (FILE, "section ~rodata,\"x\"\n"); \ + fprintf (FILE, "text\n"); \ + } while (0) + +#define ASM_OUTPUT_SOURCE_LINE(FILE, LINENO) \ + fprintf (FILE, "\tln\t%d\n", \ + (sdb_begin_function_line \ + ? last_linenum - sdb_begin_function_line : 1)) + +#undef ASM_OUTPUT_IDENT +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "\tident\t\"%s\" \n", NAME) + +#define ASM_OUTPUT_ASCII(FILE,PTR,LEN) \ + do { register int sp = 0, lp = 0; \ + fprintf ((FILE), "\tbyte\t"); \ + loop: \ + if ((PTR)[sp] > ' ' && ! ((PTR)[sp] & 0x80) && (PTR)[sp] != '\\') \ + { lp += 3; \ + fprintf ((FILE), "'%c", (PTR)[sp]); } \ + else \ + { lp += 5; \ + fprintf ((FILE), "0x%x", (PTR)[sp]); } \ + if (++sp < (LEN)) \ + { if (lp > 60) \ + { lp = 0; \ + fprintf ((FILE), "\n\tbyte\t"); } \ + else \ + putc (',', (FILE)); \ + goto loop; } \ + putc ('\n', (FILE)); } while (0) + +/* Translate Motorola opcodes such as `jbeq' + into SGS/Tower opcodes such as `beq.w'. + Change `move' to `mov'. + Change `cmpm' to `cmp'. + Change `divsl' to `tdivs'. + Change `divul' to `tdivu'. + Change `ftst' to `ftest'. + Change `fmove' to `fmov'. */ + +#define ASM_OUTPUT_OPCODE(FILE, PTR) \ +{ if ((PTR)[0] == 'j' && (PTR)[1] == 'b') \ + { ++(PTR); \ + while (*(PTR) != ' ') \ + { putc (*(PTR), (FILE)); ++(PTR); } \ + fprintf ((FILE), ".w"); } \ + else if ((PTR)[0] == 'm' && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'e') \ + { fprintf ((FILE), "mov"); (PTR) += 4; } \ + else if ((PTR)[0] == 'c' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'p' && (PTR)[3] == 'm') \ + { fprintf ((FILE), "cmp"); (PTR) += 4; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 's' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivs"); (PTR) += 5; } \ + else if ((PTR)[0] == 'd' && (PTR)[1] == 'i' \ + && (PTR)[2] == 'v' && (PTR)[3] == 'u' \ + && (PTR)[4] == 'l') \ + { fprintf ((FILE), "tdivu"); (PTR) += 5; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 't' \ + && (PTR)[2] == 's' && (PTR)[3] == 't') \ + { fprintf ((FILE), "ftest"); (PTR) += 4; } \ + else if ((PTR)[0] == 'f' && (PTR)[1] == 'm' \ + && (PTR)[2] == 'o' && (PTR)[3] == 'v' \ + && (PTR)[4] == 'e') \ + { fprintf ((FILE), "fmov"); (PTR) += 5; } \ +} + + + +/* Override parts of m68k.h to fit the Tower assembler. + This section needs to track changes done to m68k.h in the future. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (68k, Motorola/SGS/Tower32 syntax)"); + +#undef FUNCTION_BLOCK_PROFILER +#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + do { \ + char label1[20], label2[20]; \ + ASM_GENERATE_INTERNAL_LABEL (label1, "LPBX", 0); \ + ASM_GENERATE_INTERNAL_LABEL (label2, "LPI", LABELNO); \ + fprintf (FILE, "\ttst.l %s\n\tbne %s\n\tpea %s\n\tjsr __bb_init_func\n\taddq.l &4,%%sp\n", \ + label1, label2, label1); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "LPI", LABELNO); \ + putc ('\n', FILE); \ + } while (0) + +#undef BLOCK_PROFILER +#define BLOCK_PROFILER(FILE, BLOCKNO) \ + do { \ + char label[20]; \ + ASM_GENERATE_INTERNAL_LABEL (label, "LPBX", 2); \ + fprintf (FILE, "\taddq.l &1,%s+%d\n", label, 4 * BLOCKNO); \ + } while (0) + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABEL_NO) \ + fprintf (FILE, "\tmov.l &LP%%%d,%%a0\n\tjsr mcount%%\n", (LABEL_NO)) + +#undef FUNCTION_EXTRA_EPILOGUE +#define FUNCTION_EXTRA_EPILOGUE(FILE, SIZE) \ + { extern int current_function_returns_pointer; \ + if ((current_function_returns_pointer) && \ + ! find_equiv_reg (0, get_last_insn (), 0, 0, 0, 8, Pmode)) \ + asm_fprintf (FILE, "\tmov.l %Rd0,%Ra0\n"); } + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tmov.l %s,-(%%sp)\n", reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tmov.l (%%sp)+,%s\n", reg_names[REGNO]) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ +( fprintf (FILE, "#NO_APP\n"), \ + output_file_directive ((FILE), main_input_filename)) + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "text" + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "data" + +/* This says how to output an assembler line to define a global common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* This says how to output an assembler line to define a local common symbol. + We use SIZE rather than ROUNDED, as this is what the native cc does. */ + +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ +( fputs ("\tlcomm ", (FILE)), \ + assemble_name ((FILE), (NAME)), \ + fprintf ((FILE), ",%d\n", ((SIZE) == 0) ? (ROUNDED) : (SIZE))) + +/* Store in OUTPUT a string (made with alloca) containing + an assembler-name for a local static variable named NAME. + LABELNO is an integer which is different for each call. */ + +#undef ASM_FORMAT_PRIVATE_NAME +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 11), \ + sprintf ((OUTPUT), "%s%%%%%d", (NAME), (LABELNO))) + +/* This is the command to make the user-level label named NAME + defined for reference from other files. */ + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "global" + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf ((LABEL), "%s%%%d", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf ((FILE), "%s%%%d:\n", (PREFIX), (NUM)) + +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \ + fprintf (FILE, "\tswbeg &%d\n%s%%%d:\n", \ + XVECLEN (PATTERN (TABLE), 1), (PREFIX), (NUM)); \ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tlong 0x%x,0x%x\n", l[0], l[1]); \ + } while (0) + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long l[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ + fprintf (FILE, "\tlong 0x%x,0x%x,0x%x\n", l[0], l[1], l[2]); \ + } while (0) + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ + fprintf ((FILE), "\tlong 0x%x\n", l); \ + } while (0) + +/* This is how to output an assembler line defining an `int' constant. */ + +#undef ASM_OUTPUT_INT +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "\tlong "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* Likewise for `char' and `short' constants. */ + +#undef ASM_OUTPUT_SHORT +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "\tshort "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +#undef ASM_OUTPUT_CHAR +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "\tbyte "), \ + output_addr_const (FILE, (VALUE)), \ + fprintf (FILE, "\n")) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#undef ASM_OUTPUT_BYTE +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf (FILE, "\tbyte 0x%x\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_VEC_ELT +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\tlong L%%%d\n", (VALUE)) + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\tshort L%%%d-L%%%d\n", (VALUE), (REL)) + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG) == 1) \ + fprintf (FILE, "\teven\n"); \ + else if ((LOG) != 0) \ + abort (); + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\tspace %d\n", (SIZE)) + +/* Output a float value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ + +#undef ASM_OUTPUT_FLOAT_OPERAND +#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE) \ + do { long l; \ + REAL_VALUE_TO_TARGET_SINGLE (r, l); \ + /* Use hex representation even if CODE is f. as needs it. */ \ + fprintf ((FILE), "&0x%lx", l); \ + } while (0) + +/* Output a double value (represented as a C double) as an immediate operand. + This macro is a 68k-specific macro. */ +#undef ASM_OUTPUT_DOUBLE_OPERAND +#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE) \ + do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf ((FILE), "&0x%lx%08lx", l[0], l[1]); \ + } while (0) + +#if 0 +#undef PRINT_OPERAND +#define PRINT_OPERAND(FILE, X, CODE) \ +{ if (CODE == '.') fprintf (FILE, "."); \ + else if (CODE == '#') fprintf (FILE, "&"); \ + else if (CODE == '-') fprintf (FILE, "-(%%sp)"); \ + else if (CODE == '+') fprintf (FILE, "(%%sp)+"); \ + else if (CODE == '@') fprintf (FILE, "(%%sp)"); \ + else if (CODE == '!') fprintf (FILE, "%%fpcr"); \ + else if (CODE == '/') \ + fprintf (FILE, "%%"); \ + else if (CODE == '$') { if (TARGET_68040_ONLY) fprintf (FILE, "s"); } \ + else if (CODE == '&') { if (TARGET_68040_ONLY) fprintf (FILE, "d"); } \ + 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 if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \ + { REAL_VALUE_TYPE r; long l; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + REAL_VALUE_TO_TARGET_SINGLE (r, l); \ + fprintf (FILE, "&0x%x", l); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == DFmode) \ + { REAL_VALUE_TYPE r; int i[2]; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + REAL_VALUE_TO_TARGET_DOUBLE (r, i); \ + fprintf (FILE, "&0x%x%08x", i[0], i[1]); } \ + else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == XFmode) \ + { REAL_VALUE_TYPE r; \ + REAL_VALUE_FROM_CONST_DOUBLE (r, X); \ + ASM_OUTPUT_LONG_DOUBLE_OPERAND (FILE, r); } \ + else { putc ('&', FILE); output_addr_const (FILE, X); }} +#endif + +/* Note that this contains a kludge that knows that the only reason + we have an address (plus (label_ref...) (reg...)) + is in the insn before a tablejump, and we know that the table is + exactly 10 bytes away. */ + +#undef PRINT_OPERAND_ADDRESS +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ +{ register rtx reg1, reg2, breg, ireg; \ + register rtx addr = ADDR; \ + rtx offset; \ + switch (GET_CODE (addr)) \ + { \ + case REG: \ + fprintf (FILE, "(%s)", reg_names[REGNO (addr)]); \ + break; \ + case PRE_DEC: \ + fprintf (FILE, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case POST_INC: \ + fprintf (FILE, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); \ + break; \ + case PLUS: \ + reg1 = 0; reg2 = 0; \ + ireg = 0; breg = 0; \ + offset = 0; \ + if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) \ + { \ + offset = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) \ + { \ + offset = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + if (GET_CODE (addr) != PLUS) ; \ + else if (GET_CODE (XEXP (addr, 0)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == SIGN_EXTEND) \ + { \ + reg1 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + 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 \ + || GET_CODE (addr) == SIGN_EXTEND) \ + { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } \ +/* for OLD_INDEXING \ + else if (GET_CODE (addr) == PLUS) \ + { \ + if (GET_CODE (XEXP (addr, 0)) == REG) \ + { \ + reg2 = XEXP (addr, 0); \ + addr = XEXP (addr, 1); \ + } \ + else if (GET_CODE (XEXP (addr, 1)) == REG) \ + { \ + reg2 = XEXP (addr, 1); \ + addr = XEXP (addr, 0); \ + } \ + } \ + */ \ + if (offset != 0) { if (addr != 0) abort (); addr = offset; } \ + if ((reg1 && (GET_CODE (reg1) == SIGN_EXTEND \ + || GET_CODE (reg1) == MULT)) \ + || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2)))) \ + { breg = reg2; ireg = reg1; } \ + else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1))) \ + { breg = reg1; ireg = reg2; } \ + if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) \ + { int scale = 1; \ + if (GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "10(%%pc,%s.w", \ + reg_names[REGNO (XEXP (ireg, 0))]); \ + else \ + fprintf (FILE, "10(%%pc,%s.l", \ + reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; } \ + if (ireg != 0 || breg != 0) \ + { int scale = 1; \ + if (breg == 0) \ + abort (); \ + if (addr != 0) \ + output_addr_const (FILE, addr); \ + fprintf (FILE, "(%s", reg_names[REGNO (breg)]); \ + if (ireg != 0) \ + putc (',', FILE); \ + if (ireg != 0 && GET_CODE (ireg) == MULT) \ + { scale = INTVAL (XEXP (ireg, 1)); \ + ireg = XEXP (ireg, 0); } \ + if (ireg != 0 && GET_CODE (ireg) == SIGN_EXTEND) \ + fprintf (FILE, "%s.w", reg_names[REGNO (XEXP (ireg, 0))]); \ + else if (ireg != 0) \ + fprintf (FILE, "%s.l", reg_names[REGNO (ireg)]); \ + if (scale != 1) fprintf (FILE, "*%d", scale); \ + putc (')', FILE); \ + break; \ + } \ + else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF) \ + { fprintf (FILE, "10(%%pc,%s.w)", \ + reg_names[REGNO (reg1)]); \ + break; } \ + default: \ + output_addr_const (FILE, addr); \ + }} + + + +/* Override usual definitions of SDB output macros. + These definitions differ only in the absence of the period + at the beginning of the name of the directive + and in the use of `~' as the symbol for the current location. */ + +#define PUT_SDB_SCL(a) fprintf(asm_out_file, "\tscl\t%d;", (a)) +#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\tval\t%d;", (a)) +#define PUT_SDB_VAL(a) \ +( fputs ("\tval\t", asm_out_file), \ + output_addr_const (asm_out_file, (a)), \ + fputc (';', asm_out_file)) + +#define PUT_SDB_DEF(a) \ +do { fprintf (asm_out_file, "\tdef\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\tdef\t~%s;",a) +#define PUT_SDB_ENDEF fputs("\tendef\n", asm_out_file) +#define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\ttype\t0%o;", a) +#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\tsize\t%d;", a) +#define PUT_SDB_START_DIM fprintf(asm_out_file, "\tdim\t") +#define PUT_SDB_NEXT_DIM(a) fprintf(asm_out_file, "%d,", a) +#define PUT_SDB_LAST_DIM(a) fprintf(asm_out_file, "%d;", a) + +#define PUT_SDB_TAG(a) \ +do { fprintf (asm_out_file, "\ttag\t"); \ + ASM_OUTPUT_LABELREF (asm_out_file, a); \ + fprintf (asm_out_file, ";"); } while (0) + +#define PUT_SDB_BLOCK_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_BLOCK_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~eb;\tval\t~;\tscl\t100;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_START(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~bf;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_FUNCTION_END(LINE) \ + fprintf (asm_out_file, \ + "\tdef\t~ef;\tval\t~;\tscl\t101;\tline\t%d;\tendef\n", \ + (LINE)) + +#define PUT_SDB_EPILOGUE_END(NAME) \ + fprintf (asm_out_file, \ + "\tdef\t%s;\tval\t~;\tscl\t-1;\tendef\n", \ + (NAME)) + +#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \ + sprintf ((BUFFER), "~%dfake", (NUMBER)); + +#define NO_DOLLAR_IN_LABEL +#define NO_DOT_IN_LABEL + +/* The usual definitions don't work because neither $ nor . is allowed. */ +#define CONSTRUCTOR_NAME_FORMAT "_GLOBAL_%%I\%%%s" + +/* Define a few machine-specific details + of the implementation of constructors. + + The __CTORS_LIST__ goes in the .init section. Define CTOR_LIST_BEGIN + and CTOR_LIST_END to contribute to the .init section an instruction to + push a word containing 0 (or some equivalent of that). + + ASM_OUTPUT_CONSTRUCTOR should be defined + to push the address of the constructor. */ + +#define ASM_LONG "\tlong" +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP "section\t~init" +#undef FINI_SECTION_ASM_OP +#define FINI_SECTION_ASM_OP "section\t~fini" +#undef CONST_SECTION_ASM_OP +#define CONST_SECTION_ASM_OP "section\t~rodata" + +#define CTOR_LIST_BEGIN \ + asm (INIT_SECTION_ASM_OP); \ + asm ("clr.l -(%sp)") +#define CTOR_LIST_END CTOR_LIST_BEGIN + +#define BSS_SECTION_ASM_OP "section\t~bss" + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + init_section (); \ + fprintf (FILE, "\tmov.l &"); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, ",-(%%sp)\n"); \ + } while (0) diff --git a/gcc/config/m68k/tower.h b/gcc/config/m68k/tower.h new file mode 100755 index 0000000..73faedb --- /dev/null +++ b/gcc/config/m68k/tower.h @@ -0,0 +1,104 @@ +/* Definitions of target machine for GNU compiler. + Copyright (C) 1990, 1994, 1996 Free Software Foundation, Inc. + Contributed by Robert Andersson, International Systems, Oslo, ra@intsys.no. + +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. */ + +/* For NCR Tower 32/4x0 and 32/6x0 running System V Release 3. I don't have + access to 200/700/800/850 machines, so I don't know if it works on those + as well. It shouldn't be far from it however. The hardware floating point + support is completely untested, as I do not have access to a machine with + a 6888x FPU in it. It does not work on the System V Release 2 based OS + releases. Making it work will not be easy, due to the silly way in which + stack expansion is implemented in the OS. + + This file is included in tower-as.h. + Do *NOT* include this file directly. */ + + +#include "m68k/m68k.h" + +#define TARGET_DEFAULT (MASK_BITFIELD|MASK_68020) + +/* Don't try using XFmode. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_200 -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" + +#if 0 /* It is incorrect to test these symbols. + They describe the host, not the target. + It should not matter which model is specified. */ +#ifdef tower32_600 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_600 -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef tower32_700 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_700 -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef tower32_800 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_800 -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +#endif +#ifdef tower32_850 +#define CPP_PREDEFINES "-Dunix -Dtower32 -Dtower32_850 -Asystem(unix) -Asystem(svr3) -Acpu(m68k) -Amachine(m68k)" +#endif +#endif + +/* The startfiles and libraries depend on the -p and -m68881 options. + The Tower does not support the -pg option. */ + +#define LINK_SPEC \ +"%{p:%{m68881:-L/usr/lib/fp/libp} -L/usr/lib/libp} \ + %{m68881:-L/usr/lib/fp}" + +#define LIB_SPEC \ +"%{shlib:-lc_s} -lc crtend.o%s crtn.o%s" + +#define STARTFILE_SPEC \ +"%{p:mcrt1.o%s} %{!p:crt1.o%s} crtbegin.o%s" + +/* Use mem* functions, recognize #ident lines. */ + +#define TARGET_MEM_FUNCTIONS +#define IDENT_DIRECTIVE + +/* Every structure and union's size must be a multiple of two bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* All register names should have a leading % character. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES \ +{"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%sp", \ + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7"}; + +#undef REGISTER_PREFIX +#define REGISTER_PREFIX "%" + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "&" + +/* The prefix to add to user-visible assembler symbols. */ + +/* We do not want leading underscores. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" diff --git a/gcc/config/m68k/vxm68k.h b/gcc/config/m68k/vxm68k.h new file mode 100755 index 0000000..063ded8 --- /dev/null +++ b/gcc/config/m68k/vxm68k.h @@ -0,0 +1,101 @@ +/* Definitions of target machine for GNU compiler. Vxworks m68k version. + Copyright (C) 1994, 1996, 1997 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. */ + +/* This comment is here to see if it will keep Sun's cpp from dying. */ + +#include "m68k/m68k-none.h" +#include "aoutos.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dmc68000 -D__vxworks -D__vxworks_5 -Acpu(m68k) -Amachine(m68k)" + +/* The default value for -DCPU=. */ +#if TARGET_CPU_DEFAULT == M68K_CPU_m68k || TARGET_CPU_DEFAULT == M68K_CPU_m68020 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68020" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68000 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68000" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68030 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68030" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68040 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68040" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68302 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68302" +#else +#if TARGET_CPU_DEFAULT == M68K_CPU_m68332 +#define CPP_SUBTARGET_CPU_DEFAULT_SPEC "-DCPU=MC68332" +#else +Unrecognized value in TARGET_CPU_DEFAULT. +#endif +#endif +#endif +#endif +#endif +#endif + +#undef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS \ +{ "cpp_subtarget_cpu_default", CPP_SUBTARGET_CPU_DEFAULT_SPEC } + +/* Vxworks header files require that the macro CPU be set. */ +/* ??? The previous code didn't set CPU if -ansi. */ +#undef CPP_SUBTARGET_SPEC +#define CPP_SUBTARGET_SPEC "\ +%{m68000:-DCPU=MC68000 }%{m68010:-DCPU=MC68010 }%{m68020:-DCPU=MC68020 }%{mc68020:-DCPU=MC68020 }%{m68030:-DCPU=MC68030 }%{m68040:-DCPU=MC68040 }%{m68020-40:-DCPU=MC68020 }%{m68302:-DCPU=MC68000 }%{m68332:-DCPU=CPU32 } \ +%{!mc68000:%{!m68000:%{!m68010:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68020-40:%{!m68302:%{!m68332:%(cpp_subtarget_cpu_default) }}}}}}}}}} \ +" + +#define DBX_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO + +/* These are the official values from WRS. */ +#undef WCHAR_TYPE +#define WCHAR_TYPE "char" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 8 +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +/* VxWorks does all the library stuff itself. */ + +#define LIB_SPEC "" + +/* Provide required defaults for linker -e. */ + +#define LINK_SPEC "%{!nostdlib:%{!r*:%{!e*:-e start}}}" + +/* VxWorks provides the functionality of crt0.o and friends itself. */ + +#define STARTFILE_SPEC "" + +/* Every structure or union's size must be a multiple of 2 bytes. */ + +#define STRUCTURE_SIZE_BOUNDARY 16 + +/* Allow folding division by zero. */ +#define REAL_INFINITY + +/* GCC is the primary compiler for VxWorks, so we don't need this. */ +#undef PCC_STATIC_STRUCT_RETURN diff --git a/gcc/config/m68k/x-alloca-c b/gcc/config/m68k/x-alloca-c new file mode 100755 index 0000000..3375d42 --- /dev/null +++ b/gcc/config/m68k/x-alloca-c @@ -0,0 +1 @@ +ALLOCA=alloca.o diff --git a/gcc/config/m68k/x-amix b/gcc/config/m68k/x-amix new file mode 100755 index 0000000..6ec4f63 --- /dev/null +++ b/gcc/config/m68k/x-amix @@ -0,0 +1,27 @@ +# Makefile configuration for Commodore Amiga running SVR4. +# (configure amiga-amix) + +# The Amiga ships with gcc installed, so use it as the default CC. + +CC = /usr/public/bin/gcc + +# The AT&T compiler is still available in /usr/ccs/bin/cc and should +# be used to compile the things that should not be compiled with gcc. + +OLDCC = /usr/ccs/bin/cc + +# Link the executables with -ansi to get ANSI floating point ranges. +# Otherwise the values returned on overflow or underflow will be wrong. +# NOTE: some early releases of Amiga Unix contained a bug in ptod.o +# that prevents the correct values being returned from strtod/atof, even +# when linked with -ansi. Sometimes -static will fix this since at least +# one version had a fixed copy in the static libc.a. + +LDFLAGS = -ansi + +# The manual pages go in /usr/man/1l (section 1, local) without any filename +# extension. The man command will automatically create the /usr/catman/1l +# entry. + +mandir = /usr/man/1l +manext = diff --git a/gcc/config/m68k/x-apollo68 b/gcc/config/m68k/x-apollo68 new file mode 100755 index 0000000..4c809f9 --- /dev/null +++ b/gcc/config/m68k/x-apollo68 @@ -0,0 +1,15 @@ +# x-apollo68 -- 680x0 based Apollos as host system + +# vasta@apollo.com says this is how to compile on an Apollo (SR10.x). +# Use a Berkeley environment. +CC=cc -g -A nansi -A cpu,3000 -A runtype,bsd4.3 -A systype,any -DSHORT_ENUM_BUG +OLDCC=cc -g -A nansi -A cpu,3000 -A runtype,bsd4.3 -A systype,any -DSHORT_ENUM_BUG + +# This used to redefine CFLAGS and LIBGCC2_CFLAGS to eliminate the unsupported +# -g flag from both macros. This gives an undebuggable stage1 compiler which +# is bad, and it also does the wrong thing if we are cross compiling to a +# target which does support debugging. There is currently no way to avoid +# the -g option that doesn't break something else. + +# Apollo does not have B option. +TAROUTOPTS=xpf diff --git a/gcc/config/m68k/x-apollo68v b/gcc/config/m68k/x-apollo68v new file mode 100755 index 0000000..ccb76c1 --- /dev/null +++ b/gcc/config/m68k/x-apollo68v @@ -0,0 +1,5 @@ +# vasta@apollo.com says this is how to compile on an Apollo (SR10.x). +# Use a Berkeley environment. +CC=cc -g -A nansi -A cpu,3000 -A runtype,any -A systype,any -DSHORT_ENUM_BUG -DUSG -U__STDC__ +OLDCC=cc -g -A nansi -A cpu,3000 -A runtype,bsd4.3 -A systype,any -DSHORT_ENUM_BUG -DUSG -U__STDC__ + diff --git a/gcc/config/m68k/x-ccur b/gcc/config/m68k/x-ccur new file mode 100755 index 0000000..0f94e9d --- /dev/null +++ b/gcc/config/m68k/x-ccur @@ -0,0 +1,3 @@ +# Specify the jobs library when building in the ATT universe. +CLIB = -ljobs +X_CFLAGS = -O0 -DSHORT_ENUM_BUG -Dregister= diff --git a/gcc/config/m68k/x-crds b/gcc/config/m68k/x-crds new file mode 100755 index 0000000..172909c --- /dev/null +++ b/gcc/config/m68k/x-crds @@ -0,0 +1,7 @@ +CC = cc -Wx,-X23 + +# The following line might be necessary as well or instead of the above. +# If you find out that it is necessary, +# or if you find out that it is not necessary, +# please inform bug-gcc@prep.ai.mit.edu. +# ALLOCA = alloca.o diff --git a/gcc/config/m68k/x-dpx2 b/gcc/config/m68k/x-dpx2 new file mode 100755 index 0000000..a4a8c1b --- /dev/null +++ b/gcc/config/m68k/x-dpx2 @@ -0,0 +1,16 @@ +# need this when using cc +ALLOCA = alloca.o +# avoid lossage assembling alloca. +ALLOCA_FLAGS=-S +ALLOCA_FINISH = $(AS) -o alloca.o alloca.s +# be sure not to confuse ./as with /bin/as +AS=`if [ x$(OLDCC) = x$(CC) ] ; then echo /bin/as; else echo $(GAS); fi` +GAS = gas +# +# as of gcc-2.2.1 gcc -g produces too many .stabd's for /bin/ld +# to link cc1plus, so use -g with /bin/cc, but -O with gcc +CFLAGS=`if [ x$(OLDCC) = x$(CC) ] ; then echo -g; else echo -O; fi` +# +CLIB=-lmalloc -lld -lm +# tell CC whether we are a 200 or 300 +X_CFLAGS=-D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BULL_SOURCE -D__DPX2__ `if [ -d /makesys/kernel/cf/ncl_mr ]; then echo -Dncl_mr=1; else echo -Dncl_el; fi` diff --git a/gcc/config/m68k/x-hp2bsd b/gcc/config/m68k/x-hp2bsd new file mode 100755 index 0000000..7dd651c --- /dev/null +++ b/gcc/config/m68k/x-hp2bsd @@ -0,0 +1,4 @@ +# Make assignments for compilation for hp200 running 4.3bsd +CC=gcc +OLDCC=oldcc +# You must have a previous version of gcc for bootstrapping diff --git a/gcc/config/m68k/x-hp320 b/gcc/config/m68k/x-hp320 new file mode 100755 index 0000000..46f68e6 --- /dev/null +++ b/gcc/config/m68k/x-hp320 @@ -0,0 +1,17 @@ +# Make assignments for compilation on HPUX with their C compiler. +CC=cc -Wc,-Nw2000 -Wc,-Ns2000 -Wc,-Ne700 -Wc,-Np300 +OLDCC=cc -Wc,-Nw2000 -Wc,-Ns2000 -Wc,-Ne700 -Wc,-Np300 +ALLOCA=alloca.o +# B option not supported on hpux. +TAROUTOPTS = xpf + +# For CCLIBFLAGS you might want to specify the switch that +# forces only 68000 instructions to be used. + +# Version 5 of HPUX had a compiler bug that made it crash with -g. +# You must set CFLAGS to empty on version 5. + +# You must get alloca.c from GNU Emacs. + +# So putenv and other functions get seen by fixproto. +FIXPROTO_DEFINES = -D_HPUX_SOURCE diff --git a/gcc/config/m68k/x-hp320g b/gcc/config/m68k/x-hp320g new file mode 100755 index 0000000..38f201e --- /dev/null +++ b/gcc/config/m68k/x-hp320g @@ -0,0 +1,17 @@ +# Make assignments for compilation on HPUX with their C compiler. +CC=cc -Wc,-Nw2000 -Wc,-Ns2000 -Wc,-Ne700 -Wc,-Np300 +OLDCC=cc -Wc,-Nw2000 -Wc,-Ns2000 -Wc,-Ne700 -Wc,-Np300 +ALLOCA=alloca.o +# B option not supported on hpux. +TAROUTOPTS = xpf + +# For CCLIBFLAGS you might want to specify the switch that +# forces only 68000 instructions to be used. + +X_CFLAGS= -I../hp-include + +# Version 5 of HPUX had a compiler bug that made it crash with -g. +# You must set CFLAGS to empty on version 5. + +# So putenv and other functions get seen by fixproto. +FIXPROTO_DEFINES = -D_HPUX_SOURCE diff --git a/gcc/config/m68k/x-hp3bsd44 b/gcc/config/m68k/x-hp3bsd44 new file mode 100755 index 0000000..b8dffd0 --- /dev/null +++ b/gcc/config/m68k/x-hp3bsd44 @@ -0,0 +1 @@ +USER_H = $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) diff --git a/gcc/config/m68k/x-mot3300 b/gcc/config/m68k/x-mot3300 new file mode 100755 index 0000000..3d7e3c3 --- /dev/null +++ b/gcc/config/m68k/x-mot3300 @@ -0,0 +1,15 @@ +ALLOCA=alloca.o + +# This disables the long/short jump optimization. +# I use sysV68 R3V7.1 RM04 (phdm@info.ucl.ac.be) +# Since ss-950318, with jump optimization enabled, "as" issues a warning +# when assembling combine.s : +# aline nnnnn : Warning: Table overflow: some optimizations lost (SDIs) +# but later "ld" complains with +# ld: relocation entry found for non-relocatable symbol in combine.o +# and the produced "cc1" fails with SIGSEGV +# Another possible fix would be to split combine.c. +# Since ss-961013, the same happens for expr.c compiled by gcc, but not by cc; +# and for cp/decl.c; aren't those files too big ? +# With egcs-970910, this also happens for f/expr.o and f/stb.o +XCFLAGS=`case $@ in combine.o|expr.o|decl.o|f/expr.o|f/stb.o) echo -Wa,-j;;esac` diff --git a/gcc/config/m68k/x-mot3300-gas b/gcc/config/m68k/x-mot3300-gas new file mode 100755 index 0000000..cf27977 --- /dev/null +++ b/gcc/config/m68k/x-mot3300-gas @@ -0,0 +1,12 @@ +ALLOCA=alloca.o + +# This disables the long/short jump optimization. +# I use sysV68 R3V7.1 RM04 (phdm@info.ucl.ac.be) +# Since ss-950318, with jump optimization enabled, "as" issues a warning +# when assembling combine.s : +# aline nnnnn : Warning: Table overflow: some optimizations lost (SDIs) +# but later "ld" complains with +# ld: relocation entry found for non-relocatable symbol in combine.o +# and the produced "cc1" fails with SIGSEGV +# Another possible fix would be to split combine.c. +XCFLAGS=`if [ x$@ = xcombine.o -a "${CC}" = "${OLDCC}" ]; then echo -Wa,-j; fi` diff --git a/gcc/config/m68k/x-next b/gcc/config/m68k/x-next new file mode 100755 index 0000000..f1a9836 --- /dev/null +++ b/gcc/config/m68k/x-next @@ -0,0 +1,13 @@ +# Make assignments for compiling on NeXT with their compiler version. +CC=cc -traditional-cpp +OLDCC=CC -traditional-cpp + +# Specify other dirs of system header files to be fixed. +OTHER_FIXINCLUDES_DIRS= /LocalDeveloper/Headers + +# <limits.h> is sometimes in /usr/include/ansi/limits.h. +LIMITS_H_TEST = [ -f $(SYSTEM_HEADER_DIR)/limits.h -o -f $(SYSTEM_HEADER_DIR)/ansi/limits.h ] + +# f771 is so big, we need to tell linker on m68k-next-nextstep* to +# make enough room for it. +BOOT_LDFLAGS=-segaddr __DATA 6000000 diff --git a/gcc/config/m68k/x-sun3 b/gcc/config/m68k/x-sun3 new file mode 100755 index 0000000..b3ee2ce --- /dev/null +++ b/gcc/config/m68k/x-sun3 @@ -0,0 +1 @@ +INSTALL_FLOAT_H = diff --git a/gcc/config/m68k/x-tower b/gcc/config/m68k/x-tower new file mode 100755 index 0000000..995e72b --- /dev/null +++ b/gcc/config/m68k/x-tower @@ -0,0 +1,9 @@ +# On the NCR Tower 32 running SVR3, says ra@intsys.no : +# Do *not* enable optimization in CFLAGS when using the native cc, because: +# a) The optimizer seems to loop when invoked with -O2. +# b) The -O1 level does stack/frame pointer optimizations that make the +# assembler alloca in libPW.a fail, and the C alloca eats *lots* of memory. +# c) gcc will eventually be recompiled with itself, so all this doesn't matter. +X_CFLAGS = -O0 +CCLIBFLAGS = -O2 +CLIB = -lmalloc -lPW diff --git a/gcc/config/m68k/xm-3b1.h b/gcc/config/m68k/xm-3b1.h new file mode 100755 index 0000000..035004f --- /dev/null +++ b/gcc/config/m68k/xm-3b1.h @@ -0,0 +1,4 @@ +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) diff --git a/gcc/config/m68k/xm-altos3068.h b/gcc/config/m68k/xm-altos3068.h new file mode 100755 index 0000000..f540924 --- /dev/null +++ b/gcc/config/m68k/xm-altos3068.h @@ -0,0 +1,3 @@ +#define USG + +#include "m68k/xm-m68k.h" diff --git a/gcc/config/m68k/xm-amix.h b/gcc/config/m68k/xm-amix.h new file mode 100755 index 0000000..c28ed78 --- /dev/null +++ b/gcc/config/m68k/xm-amix.h @@ -0,0 +1,45 @@ +/* Definitions of host machine for GNU compiler. + Commodore Amiga A3000UX version. + Copyright (C) 1991, 1997 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 1, 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 "m68k/xm-m68kv.h" /* Use the System V flavor of m68k host */ + +#define rindex strrchr +#define index strchr + +/* Define FULL_PROTOTYPES for protoize.c, to get <unistd.h> included. + We need this file for things like R_OK, not necessarily prototypes. */ + +#define FULL_PROTOTYPES + +#if defined (__GNUC__) && __GNUC__ == 1 +#define alloca __builtin_alloca +#endif + +#if 0 /* I don't want individual ports to be inconsistent about this. + I regard fancy_abort as a half-solution and not the right way + to do things. --rms. */ +/* The m88k and mips ports make use of fancy_abort to give possibly helpful + abort information rather than just dumping core. They do it in their + tm-* files. It seems more logical that this is a characteristic of + the host machine and not the target machine, so we do it here. */ + +#define abort fancy_abort /* give possibly helpful abort info */ +#endif diff --git a/gcc/config/m68k/xm-atari.h b/gcc/config/m68k/xm-atari.h new file mode 100755 index 0000000..59f4664 --- /dev/null +++ b/gcc/config/m68k/xm-atari.h @@ -0,0 +1,5 @@ +/* Add HZ define if missing */ + +#ifndef HZ +#define HZ 100 /* System clock */ +#endif diff --git a/gcc/config/m68k/xm-aux.h b/gcc/config/m68k/xm-aux.h new file mode 100755 index 0000000..5ac1f46 --- /dev/null +++ b/gcc/config/m68k/xm-aux.h @@ -0,0 +1,9 @@ +#ifndef USG +#define USG +#endif + +#ifndef AUX +#define AUX +#endif + +#include "m68k/xm-m68k.h" diff --git a/gcc/config/m68k/xm-crds.h b/gcc/config/m68k/xm-crds.h new file mode 100755 index 0000000..2bf1bdb --- /dev/null +++ b/gcc/config/m68k/xm-crds.h @@ -0,0 +1,7 @@ +/* Avoid conflict with C library by changing name of this symbol. */ +#define gettime gcc_gettime + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) diff --git a/gcc/config/m68k/xm-hp320.h b/gcc/config/m68k/xm-hp320.h new file mode 100755 index 0000000..f3009a6 --- /dev/null +++ b/gcc/config/m68k/xm-hp320.h @@ -0,0 +1,13 @@ +/* USG is needed to prevent trying to use getrusage and getwd. */ +#define USG + +#include "m68k/xm-m68k.h" + +/* If compiling with HPUX compiler, we are probably using alloca.c, + so help it work right. */ +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif + +/* Don't try to use sys_siglist. */ +#define NO_SYS_SIGLIST diff --git a/gcc/config/m68k/xm-linux.h b/gcc/config/m68k/xm-linux.h new file mode 100755 index 0000000..bfac3ae --- /dev/null +++ b/gcc/config/m68k/xm-linux.h @@ -0,0 +1,4 @@ +/* Configuration for GCC for Motorola m68k running Linux-based GNU systems. */ + +#include <m68k/xm-m68k.h> +#include <xm-linux.h> diff --git a/gcc/config/m68k/xm-lynx.h b/gcc/config/m68k/xm-lynx.h new file mode 100755 index 0000000..78762b3 --- /dev/null +++ b/gcc/config/m68k/xm-lynx.h @@ -0,0 +1,35 @@ +/* Configuration for GNU C-compiler for all platforms running LynxOS. + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include <xm-lynx.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 1 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gcc/config/m68k/xm-m68k.h b/gcc/config/m68k/xm-m68k.h new file mode 100755 index 0000000..757c9af --- /dev/null +++ b/gcc/config/m68k/xm-m68k.h @@ -0,0 +1,41 @@ +/* Configuration for GNU C-compiler for Motorola 68000 family. + Copyright (C) 1987, 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* #defines that need visibility everywhere. */ +#define FALSE 0 +#define TRUE 1 + +/* 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 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ +#include "tm.h" + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 diff --git a/gcc/config/m68k/xm-m68kv.h b/gcc/config/m68k/xm-m68kv.h new file mode 100755 index 0000000..d0931f0 --- /dev/null +++ b/gcc/config/m68k/xm-m68kv.h @@ -0,0 +1,9 @@ +/* Host environment for 68000's running System V. */ + +#include "m68k/xm-m68k.h" + +#define USG + +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif diff --git a/gcc/config/m68k/xm-mot3300.h b/gcc/config/m68k/xm-mot3300.h new file mode 100755 index 0000000..ea3b558 --- /dev/null +++ b/gcc/config/m68k/xm-mot3300.h @@ -0,0 +1,41 @@ +/* Configuration for GNU C-compiler for Motorola 68000 family. + SysV68 Motorola 3300 Delta Series + Copyright (C) 1994, 1995, 1996, 1997 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. */ + + +#define USG 1 + +/* do not use alloca from -lPW with cc, because function epilogues use %sp */ +#ifndef __GNUC__ +#ifdef __STDC__ +extern void *alloca (); +#else +extern char *alloca (); +#endif +#endif + +/* Override part of the obstack macros. */ + +#define __PTR_TO_INT(P) ((int)(P)) +#define __INT_TO_PTR(P) ((char *)(P)) + +/* We need POSIX/XOPEN symbols; otherwise make check will fail. */ +#define ADD_MISSING_POSIX 1 +#define ADD_MISSING_XOPEN 1 diff --git a/gcc/config/m68k/xm-netbsd.h b/gcc/config/m68k/xm-netbsd.h new file mode 100755 index 0000000..27a33cd --- /dev/null +++ b/gcc/config/m68k/xm-netbsd.h @@ -0,0 +1,4 @@ +/* Configuration for GCC for Motorola 68k running NetBSD as host. */ + +#include <m68k/xm-m68k.h> +#include <xm-netbsd.h> diff --git a/gcc/config/m68k/xm-next.h b/gcc/config/m68k/xm-next.h new file mode 100755 index 0000000..e0b53f2 --- /dev/null +++ b/gcc/config/m68k/xm-next.h @@ -0,0 +1,3 @@ +/* malloc does better with chunks the size of a page. */ + +#define OBSTACK_CHUNK_SIZE (getpagesize ()) diff --git a/gcc/config/m68k/xm-plexus.h b/gcc/config/m68k/xm-plexus.h new file mode 100755 index 0000000..8498198 --- /dev/null +++ b/gcc/config/m68k/xm-plexus.h @@ -0,0 +1,6 @@ +/* Host environment for 68000's running System V. */ + +#ifndef _SIZE_T_ +typedef int size_t; +#define _SIZE_T_ +#endif diff --git a/gcc/config/m68k/xm-sun3.h b/gcc/config/m68k/xm-sun3.h new file mode 100755 index 0000000..eafe716 --- /dev/null +++ b/gcc/config/m68k/xm-sun3.h @@ -0,0 +1,5 @@ +/* Configuration for GCC for Motorola m68k on sun3. */ + +#define HAVE_POPEN + +#include "m68k/xm-m68k.h" diff --git a/gcc/config/m68k/xm-tower.h b/gcc/config/m68k/xm-tower.h new file mode 100755 index 0000000..fcb456f --- /dev/null +++ b/gcc/config/m68k/xm-tower.h @@ -0,0 +1,4 @@ +#include "m68k/xm-m68k.h" +#include "xm-svr3.h" + +#define HAVE_VPRINTF |