diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/config/i386 | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/config/i386')
149 files changed, 29399 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/config/i386/386bsd.h b/gnu/egcs/gcc/config/i386/386bsd.h new file mode 100644 index 00000000000..7962321325c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/386bsd.h @@ -0,0 +1,76 @@ +/* Configuration for an i386 running 386BSD as the target machine. */ + +/* This is tested by i386gas.h. */ +#define YES_UNDERSCORES + +#include "i386/gstabs.h" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -D____386BSD____ -D__386BSD__ -DBSD_NET2 -Asystem(unix) -Asystem(bsd) -Acpu(i386) -Amachine(i386)" + +/* Like the default, except no -lg. */ +#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" + +#define WCHAR_UNSIGNED 1 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +/* 386BSD does have atexit. */ + +#define HAVE_ATEXIT + +/* Redefine this to use %eax instead of %edx. */ +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%eax\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%eax\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/* The following macros are stolen from i386v4.h */ +/* These have to be defined to get PIC code correct */ + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* 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/gnu/egcs/gcc/config/i386/aix386.h b/gnu/egcs/gcc/config/i386/aix386.h new file mode 100644 index 00000000000..e0498e79595 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/aix386.h @@ -0,0 +1,69 @@ +/* Definitions for IBM PS2 running AIX/386 with gas. + From: Minh Tran-Le <TRANLE@intellicorp.com> + Copyright (C) 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. */ + +/* + * This configuration file is for gcc with gas-2.x and gnu ld 2.x + * with aix ps/2 1.3.x. + */ + +/* Define USE_GAS if you have the new version of gas that can handle + * multiple segments and .section pseudo op. This will allow gcc to + * use the .init section for g++ ctor/dtor. + * + * If you don't have gas then undefined USE_GAS. You will also have + * to use collect if you want to use g++ + */ +#define USE_GAS + +#include "i386/aix386ng.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. + And add crtbegin.o and crtend.o for ctors and dtors */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} crtbegin.o%s" +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "crtend.o%s crtn.o%s" + +/* Removed the -K flags because the gnu ld does not handle it */ +#undef LINK_SPEC +#define LINK_SPEC "%{T*} %{z:-lm}" + +/* Define a few machine-specific details of the implementation of + constructors. */ + +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP ".section .init,\"x\"" + +#define CTOR_LIST_BEGIN \ + asm (INIT_SECTION_ASM_OP); \ + asm ("pushl $0") +#define CTOR_LIST_END CTOR_LIST_BEGIN + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + init_section (); \ + fprintf (FILE, "\tpushl $"); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) diff --git a/gnu/egcs/gcc/config/i386/aix386ng.h b/gnu/egcs/gcc/config/i386/aix386ng.h new file mode 100644 index 00000000000..9a8dae632c3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/aix386ng.h @@ -0,0 +1,140 @@ +/* Definitions for IBM PS2 running AIX/386. + Copyright (C) 1988, 1996, 1998 Free Software Foundation, Inc. + Contributed by Minh Tran-Le <TRANLE@intellicorp.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 "i386/i386.h" + +/* Get the generic definitions for system V.3. */ + +#include "svr3.h" + +/* Use the ATT assembler syntax. + This overrides at least one macro (USER_LABEL_PREFIX) from svr3.h. */ + +#include "i386/att.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" +#define ENDFILE_SPEC "crtn.o%s" + +#define LIB_SPEC "%{shlib:-lc_s} -lc" + +/* Special flags for the linker. I don't know what they do. */ + +#define LINK_SPEC "%{K} %{!K:-K} %{T*} %{z:-lm}" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dps2 -Dunix -Asystem(aix)" + +#define CPP_SPEC "%(cpp_cpu) \ + %{posix:-D_POSIX_SOURCE}%{!posix:-DAIX} -D_I386 -D_AIX -D_MBCS" + +/* special flags for the aix assembler to generate the short form for all + qualifying forward reference */ +/* The buggy /bin/as of aix ps/2 1.2.x cannot always handle it. */ +#if 0 +#define ASM_SPEC "-s2" +#endif /* 0 */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { output_file_directive (FILE, main_input_filename); \ + if (optimize) \ + ASM_FILE_START_1 (FILE); \ + else \ + fprintf (FILE, "\t.noopt\n"); \ + } while (0) + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +#ifndef USE_GAS +/* Don't write a `.optim' pseudo; this assembler + is said to have a bug when .optim is used. */ + +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.noopt\n") +#endif + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tleal %sP%d,%%eax\n\tcall mcount\n", LPREFIX, (LABELNO)); + +/* Note that using bss_section here caused errors + in building shared libraries on system V.3. + but AIX 1.2 does not have yet shareable libraries on PS2 */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + (bss_section (), \ + ASM_OUTPUT_LABEL ((FILE), (NAME)), \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED))) + + +/* Undef all the .init and .fini section stuff if we are not using gas and + * gnu ld so that we can use collect because the standard /bin/as and /bin/ld + * cannot handle those. + */ +#ifndef USE_GAS +# undef INIT_SECTION_ASM_OP +# undef FINI_SECTION_ASM_OP +# undef CTORS_SECTION_ASM_OP +# undef DTORS_SECTION_ASM_OP +# undef ASM_OUTPUT_CONSTRUCTOR +# undef ASM_OUTPUT_DESTRUCTOR +# undef DO_GLOBAL_CTORS_BODY + +# undef CTOR_LIST_BEGIN +# define CTOR_LIST_BEGIN +# undef CTOR_LIST_END +# define CTOR_LIST_END +# undef DTOR_LIST_BEGIN +# define DTOR_LIST_BEGIN +# undef DTOR_LIST_END +# define DTOR_LIST_END + +# undef CONST_SECTION_FUNCTION +# define CONST_SECTION_FUNCTION \ +void \ +const_section () \ +{ \ + extern void text_section(); \ + text_section(); \ +} + +# undef EXTRA_SECTION_FUNCTIONS +# define EXTRA_SECTION_FUNCTIONS \ + CONST_SECTION_FUNCTION + +/* for collect2 */ +# define OBJECT_FORMAT_COFF +# define MY_ISCOFF(magic) \ + ((magic) == I386MAGIC || (magic) == I386SVMAGIC) + +#endif /* !USE_GAS */ diff --git a/gnu/egcs/gcc/config/i386/att.h b/gnu/egcs/gcc/config/i386/att.h new file mode 100644 index 00000000000..e5c2d9c7e99 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/att.h @@ -0,0 +1,93 @@ +/* Definitions for AT&T assembler syntax for the Intel 80386. + 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 common aspects of all 386 Unix assemblers. */ +#include "i386/unix.h" + +#define TARGET_VERSION fprintf (stderr, " (80386, ATT syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Assembler pseudos to introduce constants of various size. */ + +/* #define ASM_BYTE_OP "\t.byte" Now in svr3.h or svr4.h. */ +#define ASM_SHORT "\t.value" +#define ASM_LONG "\t.long" +#define ASM_DOUBLE "\t.double" + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +do \ +{ int i = 0; \ + while (i < (size)) \ + { if (i%10 == 0) { if (i!=0) fprintf ((FILE), "\n"); \ + fprintf ((FILE), "%s ", ASM_BYTE_OP); } \ + else fprintf ((FILE), ","); \ + fprintf ((FILE), "0x%x", ((p)[i++] & 0377)) ;} \ + fprintf ((FILE), "\n"); \ +} while (0) + +/* Do use .optim by default on this machine. */ +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* 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) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf ((FILE), "\t.set .,.+%u\n", (SIZE)) + +/* Can't use ASM_OUTPUT_SKIP in text section; it doesn't leave 0s. */ + +#define ASM_NO_SKIP_IN_TEXT 1 + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* 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) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" diff --git a/gnu/egcs/gcc/config/i386/bsd.h b/gnu/egcs/gcc/config/i386/bsd.h new file mode 100644 index 00000000000..34db79a79d5 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/bsd.h @@ -0,0 +1,128 @@ +/* Definitions for BSD assembler syntax for Intel 386 + (actually AT&T syntax for insns and operands, + adapted to BSD conventions for symbol names and debugging.) + 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 common aspects of all 386 Unix assemblers. */ +#include "i386/unix.h" + +/* Use the Sequent Symmetry assembler syntax. */ + +#define TARGET_VERSION fprintf (stderr, " (80386, BSD syntax)"); + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Prefix for internally generated assembler labels. If we aren't using + underscores, we are using prefix `.'s to identify labels that should + be ignored, as in `i386/gas.h' --karl@cs.umb.edu */ +#ifdef NO_UNDERSCORES +#define LPREFIX ".L" +#else +#define LPREFIX "L" +#endif /* not NO_UNDERSCORES */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE_OP "\t.byte" +#define ASM_SHORT "\t.word" +#define ASM_LONG "\t.long" +#define ASM_DOUBLE "\t.double" + +/* Output at beginning of assembler file. + ??? I am skeptical of this -- RMS. */ + +#define ASM_FILE_START(FILE) \ + do { output_file_directive (FILE, main_input_filename); \ + } while (0) + +/* This was suggested, but it shouldn't be right for DBX output. -- RMS + #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) */ + + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf (FILE, "\t.space %u\n", (SIZE)) + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* 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))) + +/* 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) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", (LOG)) + +/* This is how to store into the string BUF + 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'. */ + +#ifdef NO_UNDERSCORES +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) +#else +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) +#endif + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#ifdef NO_UNDERSCORES +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) +#else +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) +#endif + +/* The prefix to add to user-visible assembler symbols. */ + +#ifdef NO_UNDERSCORES +#define USER_LABEL_PREFIX "" +#else +#define USER_LABEL_PREFIX "_" +#endif /* not NO_UNDERSCORES */ + +/* Sequent has some changes in the format of DBX symbols. */ +#define DBX_NO_XREFS 1 + +/* Don't split DBX symbols into continuations. */ +#define DBX_CONTIN_LENGTH 0 diff --git a/gnu/egcs/gcc/config/i386/bsd386.h b/gnu/egcs/gcc/config/i386/bsd386.h new file mode 100644 index 00000000000..c0dcf87cbdd --- /dev/null +++ b/gnu/egcs/gcc/config/i386/bsd386.h @@ -0,0 +1,33 @@ +/* Configuration for an i386 running BSDI's BSD/OS (formerly known as BSD/386) + as the target machine. */ + +#include "i386/386bsd.h" + +/* We exist mostly to add -Dbsdi and such to the predefines. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -Dbsdi -D__i386__ -D__bsdi__ -D____386BSD____ -D__386BSD__ -DBSD_NET2 -Asystem(unix) -Asystem(bsd) -Acpu(i386) -Amachine(i386)" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +/* This is suitable for BSD/OS 3.0; we don't know about earlier releases. */ +#undef ASM_COMMENT_START +#define ASM_COMMENT_START " #" + +/* Until they use ELF or something that handles dwarf2 unwinds + and initialization stuff better. */ +#define DWARF2_UNWIND_INFO 0 + +/* BSD/OS still uses old binutils that don't insert nops by default + when the .align directive demands to insert extra space in the text + segment. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) diff --git a/gnu/egcs/gcc/config/i386/config-nt.sed b/gnu/egcs/gcc/config/i386/config-nt.sed new file mode 100644 index 00000000000..6c86b27e99c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/config-nt.sed @@ -0,0 +1,38 @@ +/^Makefile/,/^ rm -f config.run/d +s/rm -f/del/ +s/|| cp/|| copy/ +/^config.status/,/ fi/d +s/config.status//g +s/\/dev\/null/NUL/g +s/$(srcdir)\/c-parse/c-parse/g +s/$(srcdir)\/c-gperf/c-gperf/g +/^multilib.h/ s/multilib/not-multilib/ +/^target=/ c\ +target=winnt3.5 +/^xmake_file=/ d +/^tmake_file=/ d +/^out_file/ c\ +out_file=config/i386/i386.c +/^out_object_file/ c\ +out_object_file=i386.obj +/^md_file/ c\ +md_file=config/i386/i386.md +/^tm_file/ c\ +tm_file=config/i386/win-nt.h +/^build_xm_file/ c\ +build_xm_file=config/i386/xm-winnt.h +/^host_xm_file/ c\ +host_xm_file=config/i386/xm-winnt.h +/^####target/ i\ +CC = cl \ +CLIB = libc.lib kernel32.lib \ +CFLAGS = -Di386 -DWIN32 -D_WIN32 -D_M_IX86=300 -D_X86_=1 \\\ + -DALMOST_STDC -D_MSC_VER=800 \ +LDFLAGS = -align:0x1000 -subsystem:console -entry:mainCRTStartup \\\ + -stack:1000000,1000 \ +\ +EXTRA_OBJS=winnt.obj \ +winnt.obj: $(srcdir)/config/i386/winnt.c \ +\ $(CC) $(CFLAGS) \\\ +\ -I. -I$(srcdir) -I$(srcdir)/config -c $(srcdir)/config/i386/winnt.c \ + diff --git a/gnu/egcs/gcc/config/i386/crtdll.h b/gnu/egcs/gcc/config/i386/crtdll.h new file mode 100644 index 00000000000..3202af8cca8 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/crtdll.h @@ -0,0 +1,40 @@ +/* Operating system specific defines to be used when targeting GCC for + hosting on Windows32, using GNU tools and the Windows32 API Library, + as distinct from winnt.h, which is used to build GCC for use with a + windows style library and tool set and uses the Microsoft tools. + This variant uses CRTDLL.DLL insted of MSVCRTDLL.DLL. + Copyright (C) 1998, 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. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -D_WIN32 -DWIN32 -D__WIN32__ \ + -D__MINGW32__=0.2 -DWINNT -D_X86_=1 -D__STDC__=1\ + -D__stdcall=__attribute__((__stdcall__)) \ + -D_stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ + -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lcrtdll" + +/* Specify a different entry point when linking a DLL */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{mdll:dllcrt1%O%s} %{!mdll:crt1%O%s}" + diff --git a/gnu/egcs/gcc/config/i386/cygwin.asm b/gnu/egcs/gcc/config/i386/cygwin.asm new file mode 100644 index 00000000000..4ac4c91a3b1 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/cygwin.asm @@ -0,0 +1,32 @@ +/* stuff needed for libgcc1 on win32. */ + +#ifdef L_chkstk + + .global ___chkstk + .global __alloca +___chkstk: +__alloca: + pushl %ecx /* save temp */ + movl %esp,%ecx /* get sp */ + addl $0x8,%ecx /* and point to return addr */ + +probe: cmpl $0x1000,%eax /* > 4k ?*/ + jb done + + subl $0x1000,%ecx /* yes, move pointer down 4k*/ + orl $0x0,(%ecx) /* probe there */ + subl $0x1000,%eax /* decrement count */ + jmp probe /* and do it again */ + +done: subl %eax,%ecx + orl $0x0,(%ecx) /* less that 4k, just peek here */ + + movl %esp,%eax + movl %ecx,%esp /* decrement stack */ + + movl (%eax),%ecx /* recover saved temp */ + movl 4(%eax),%eax /* get return address */ + jmp *%eax + + +#endif diff --git a/gnu/egcs/gcc/config/i386/cygwin.h b/gnu/egcs/gcc/config/i386/cygwin.h new file mode 100644 index 00000000000..48b9eba1b1c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/cygwin.h @@ -0,0 +1,534 @@ +/* Operating system specific defines to be used when targeting GCC for + hosting on Windows NT 3.x, using a Unix style C library and tools, + as distinct from winnt.h, which is used to build GCC for use with a + windows style library and tool set and uses the Microsoft tools. + Copyright (C) 1995, 1996, 1997, 1998, 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. */ + +#define YES_UNDERSCORES + +#define DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "i386/gas.h" +#include "dbxcoff.h" + +/* Augment TARGET_SWITCHES with the cygwin/no-cygwin options. */ +#define MASK_WIN32 0x40000000 /* Use -lming32 interface */ +#define MASK_CYGWIN 0x20000000 /* Use -lcygwin interface */ +#define MASK_WINDOWS 0x10000000 /* Use windows interface */ +#define MASK_DLL 0x08000000 /* Use dll interface */ +#define MASK_NOP_FUN_DLLIMPORT 0x20000 /* Ignore dllimport for functions */ + +#define TARGET_WIN32 (target_flags & MASK_WIN32) +#define TARGET_CYGWIN (target_flags & MASK_CYGWIN) +#define TARGET_WINDOWS (target_flags & MASK_WINDOWS) +#define TARGET_DLL (target_flags & MASK_DLL) +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & MASK_NOP_FUN_DLLIMPORT) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ +{ "cygwin", MASK_CYGWIN, "Use the Cygwin interface" }, \ +{ "no-cygwin", MASK_WIN32, "Use the Mingw32 interface" }, \ +{ "windows", MASK_WINDOWS, "Create GUI application" }, \ +{ "console", -MASK_WINDOWS, "Create console application" }, \ +{ "dll", MASK_DLL, "Generate code for a DLL" }, \ +{ "nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, "Ignore dllimport for functions" }, \ +{ "no-nop-fun-dllimport", -MASK_NOP_FUN_DLLIMPORT, "" }, + + +/* Support the __declspec keyword by turning them into attributes. + We currently only support: dllimport and dllexport. + Note that the current way we do this may result in a collision with + predefined attributes later on. This can be solved by using one attribute, + say __declspec__, and passing args to it. The problem with that approach + is that args are not accumulated: each new appearance would clobber any + existing args. */ + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif + +#define CPP_PREDEFINES "-Di386 -D_WIN32 \ + -DWINNT -D_X86_=1 -D__STDC__=1\ + -D__stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ + -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + +/* Normally, -lgcc is not needed since everything in it is in the DLL, but we + want to allow things to be added to it when installing new versions of + GCC without making a new CYGWIN.DLL, so we leave it. Profiling is handled + by calling the init function from the prologue. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{mdll: %{mno-cygwin:dllcrt1%O%s}} \ + %{!mdll: %{!mno-cygwin:crt0%O%s} \ + %{mno-cygwin:crt1%O%s} %{pg:gcrt0%O%s}}" + +#undef CPP_SPEC +#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ + %{!mno-cygwin:-D__CYGWIN32__ -D__CYGWIN__} \ + %{mno-cygwin:-iwithprefixbefore \ + ../../../../%(mingw_include_path)/include/mingw32 -D__MINGW32__=0.2}" + +/* 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. */ + +#undef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS \ + { "mingw_include_path", DEFAULT_TARGET_MACHINE } + +/* We have to dynamic link to get to the system DLLs. All of libc, libm and + the Unix stuff is in cygwin.dll. The import library is called + 'libcygwin.a'. For Windows applications, include more libraries, but + always include kernel32. We'd like to specific subsystem windows to + ld, but that doesn't work just yet. */ + +#undef LIB_SPEC +#define LIB_SPEC "%{pg:-lgmon} \ + %{!mno-cygwin:-lcygwin} \ + %{mno-cygwin:-lmingw32 -lmoldname -lcrtdll} \ + %{mwindows:-lgdi32 -lcomdlg32} \ + -luser32 -lkernel32 -ladvapi32 -lshell32" + +#define LINK_SPEC "%{mwindows:--subsystem windows} \ + %{mconsole:--subsystem console} \ + %{mdll:--dll -e _DllMainCRTStartup@12}" + + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_UNSIGNED 1 +#define WCHAR_TYPE_SIZE 16 +#define WCHAR_TYPE "short unsigned int" + +#define HAVE_ATEXIT 1 + + +/* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop). */ +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int i386_pe_valid_decl_attribute_p (); + +#undef VALID_MACHINE_DECL_ATTRIBUTE +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ + i386_pe_valid_decl_attribute_p (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ + +#undef VALID_MACHINE_TYPE_ATTRIBUTE +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) \ + i386_pe_valid_type_attribute_p (TYPE, ATTRIBUTES, IDENTIFIER, ARGS) +extern int i386_pe_valid_type_attribute_p (); + +extern union tree_node *i386_pe_merge_decl_attributes (); +#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \ + i386_pe_merge_decl_attributes ((OLD), (NEW)) + +/* Used to implement dllexport overriding dllimport semantics. It's also used + to handle vtables - the first pass won't do anything because + DECL_CONTEXT (DECL) will be 0 so i386_pe_dll{ex,im}port_p will return 0. + It's also used to handle dllimport override semantics. */ +#if 0 +#define REDO_SECTION_INFO_P(DECL) \ + ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ + || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) +#else +#define REDO_SECTION_INFO_P(DECL) 1 +#endif + + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctor, in_dtor, in_drectve + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTOR_SECTION_FUNCTION \ + DTOR_SECTION_FUNCTION \ + DRECTVE_SECTION_FUNCTION \ + SWITCH_TO_SECTION_FUNCTION + +#define CTOR_SECTION_FUNCTION \ +void \ +ctor_section () \ +{ \ + if (in_section != in_ctor) \ + { \ + fprintf (asm_out_file, "\t.section .ctor\n"); \ + in_section = in_ctor; \ + } \ +} + +#define DTOR_SECTION_FUNCTION \ +void \ +dtor_section () \ +{ \ + if (in_section != in_dtor) \ + { \ + fprintf (asm_out_file, "\t.section .dtor\n"); \ + in_section = in_dtor; \ + } \ +} + +#define DRECTVE_SECTION_FUNCTION \ +void \ +drectve_section () \ +{ \ + if (in_section != in_drectve) \ + { \ + fprintf (asm_out_file, "%s\n", "\t.section .drectve\n"); \ + in_section = in_drectve; \ + } \ +} + +/* Switch to SECTION (an `enum in_section'). + + ??? This facility should be provided by GCC proper. + The problem is that we want to temporarily switch sections in + ASM_DECLARE_OBJECT_NAME and then switch back to the original section + afterwards. */ +#define SWITCH_TO_SECTION_FUNCTION \ +void \ +switch_to_section (section, decl) \ + enum in_section section; \ + tree decl; \ +{ \ + switch (section) \ + { \ + case in_text: text_section (); break; \ + case in_data: data_section (); break; \ + case in_named: named_section (decl, NULL, 0); break; \ + case in_ctor: ctor_section (); break; \ + case in_dtor: dtor_section (); break; \ + case in_drectve: drectve_section (); break; \ + default: abort (); break; \ + } \ +} + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Don't allow flag_pic to propagate since gas may produce invalid code + otherwise. */ + +#undef SUBTARGET_OVERRIDE_OPTIONS +#define SUBTARGET_OVERRIDE_OPTIONS \ +do { \ + if (flag_pic) \ + { \ + warning ("-f%s ignored for target (all code is position independent)",\ + (flag_pic > 1) ? "PIC" : "pic"); \ + flag_pic = 0; \ + } \ +} while (0) \ + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + On i386 running Windows NT, modify the assembler name with a suffix + consisting of an atsign (@) followed by string of digits that represents + the number of bytes of arguments passed to the function, if it has the + attribute STDCALL. + + In addition, we must mark dll symbols specially. Definitions of + dllexport'd objects install some info in the .drectve section. + References to dllimport'd objects are fetched indirectly via + _imp__. If both are declared, dllexport overrides. This is also + needed to implement one-only vtables: they go into their own + section and we need to set DECL_SECTION_NAME so we do that here. + Note that we can be called twice on the same decl. */ + +extern void i386_pe_encode_section_info (); + +#ifdef ENCODE_SECTION_INFO +#undef ENCODE_SECTION_INFO +#endif +#define ENCODE_SECTION_INFO(DECL) i386_pe_encode_section_info (DECL) + +/* Utility used only in this file. */ +#define I386_PE_STRIP_ENCODING(SYM_NAME) \ + ((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) + +/* This macro gets just the user-specified name + out of the string in a SYMBOL_REF. Discard + trailing @[NUM] encoded by ENCODE_SECTION_INFO. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ +do { \ + char *_p; \ + char *_name = I386_PE_STRIP_ENCODING (SYMBOL_NAME); \ + for (_p = _name; *_p && *_p != '@'; ++_p) \ + ; \ + if (*_p == '@') \ + { \ + int _len = _p - _name; \ + (VAR) = (char *) alloca (_len + 1); \ + strncpy ((VAR), _name, _len); \ + (VAR)[_len] = '\0'; \ + } \ + else \ + (VAR) = _name; \ +} while (0) + + +/* Output a reference to a label. */ +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(STREAM, NAME) \ + fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, \ + I386_PE_STRIP_ENCODING (NAME)) \ + +/* Output a common block. */ +#undef ASM_OUTPUT_COMMON +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ +do { \ + if (i386_pe_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + } \ + if (! i386_pe_dllimport_name_p (NAME)) \ + { \ + fprintf ((STREAM), "\t.comm\t"); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ", %d\t%s %d\n", \ + (ROUNDED), ASM_COMMENT_START, (SIZE)); \ + } \ +} while (0) + +/* Output the label for an initialized variable. */ +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ +do { \ + if (i386_pe_dllexport_name_p (NAME)) \ + { \ + enum in_section save_section = in_section; \ + drectve_section (); \ + fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + switch_to_section (save_section, (DECL)); \ + } \ + ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ +} while (0) + + +/* Emit code to check the stack when allocating more that 4000 + bytes in one go. */ + +#define CHECK_STACK_LIMIT 4000 + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387 and needs stack probes */ +#undef TARGET_DEFAULT + +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE) + +/* 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.align %d\n", 1<<(LOG)) + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void i386_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) i386_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + static struct section_info \ + { \ + struct section_info *next; \ + char *name; \ + enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \ + } *sections; \ + struct section_info *s; \ + char *mode; \ + enum sect_enum type; \ + \ + for (s = sections; s; s = s->next) \ + if (!strcmp (NAME, s->name)) \ + break; \ + \ + if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \ + type = SECT_EXEC, mode = "x"; \ + else if (DECL && DECL_READONLY_SECTION (DECL, RELOC)) \ + type = SECT_RO, mode = ""; \ + else \ + type = SECT_RW, mode = "w"; \ + \ + if (s == 0) \ + { \ + s = (struct section_info *) xmalloc (sizeof (struct section_info)); \ + s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \ + strcpy (s->name, NAME); \ + s->type = type; \ + s->next = sections; \ + sections = s; \ + fprintf (STREAM, ".section\t%s,\"%s\"\n", NAME, mode); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ + } \ + else \ + { \ + fprintf (STREAM, ".section\t%s,\"%s\"\n", NAME, mode); \ + } \ +} while (0) + +/* Write the extra assembler code needed to declare a function + properly. If we are generating SDB debugging information, this + will happen automatically, so we only need to handle other cases. */ +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + if (i386_pe_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((FILE), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + if (write_symbols != SDB_DEBUG) \ + i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) + +/* Add an external function to the list of functions to be declared at + the end of the file. */ +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + do \ + { \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + i386_pe_record_external_function (NAME); \ + } \ + while (0) + +/* Declare the type properly for any external libcall. */ +#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ + i386_pe_declare_function_type (FILE, XSTR (FUN, 0), 1) + +/* Output function declarations at the end of the file. */ +#define ASM_FILE_END(FILE) \ + i386_pe_asm_file_end (FILE) + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START " #" + +/* DWARF2 Unwinding doesn't work with exception handling yet. */ +#define DWARF2_UNWIND_INFO 0 + +/* Don't assume anything about the header files. */ +#define NO_IMPLICIT_EXTERN_C + +#define SUBTARGET_PROLOGUE \ + if (profile_flag \ + && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),\ + "main") == 0) \ + { \ + rtx xops[1]; \ + xops[0] = gen_rtx_MEM (FUNCTION_MODE, \ + gen_rtx (SYMBOL_REF, Pmode, "_monstartup")); \ + if (do_rtl) \ + emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \ + else \ + output_asm_insn (AS1 (call,%P1), xops); \ + } + +/* External function declarations. */ + +#ifndef PROTO +#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) +#define PROTO(ARGS) ARGS +#else +#define PROTO(ARGS) () +#endif +#endif + +#ifdef BUFSIZ /* stdio.h has been included, ok to use FILE * */ +#define STDIO_PROTO(ARGS) PROTO(ARGS) +#else +#define STDIO_PROTO(ARGS) () +#endif + +extern void i386_pe_record_external_function PROTO((char *)); +extern void i386_pe_declare_function_type STDIO_PROTO((FILE *, char *, int)); +extern void i386_pe_asm_file_end STDIO_PROTO((FILE *)); + +/* For Win32 ABI compatibility */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* No data type wants to be aligned rounder than this. */ +#undef BIGGEST_ALIGNMENT +#define BIGGEST_ALIGNMENT 128 + +/* A bitfield declared as `int' forces `int' alignment for the struct. */ +#undef PCC_BITFIELDS_TYPE_MATTERS +#define PCC_BITFIELDS_TYPE_MATTERS 0 + diff --git a/gnu/egcs/gcc/config/i386/dgux.c b/gnu/egcs/gcc/config/i386/dgux.c new file mode 100644 index 00000000000..638d1e0f60e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/dgux.c @@ -0,0 +1,192 @@ +/* Subroutines for GNU compiler for Intel 80x86 running DG/ux + Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc. + Currently maintained by (gcc@dg-rtp.dg.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 <time.h> +#include "i386/i386.c" + + +extern char *version_string; + +struct option +{ + char *string; + int *variable; + int on_value; + char *description; +}; + +static int +output_option (file, sep, type, name, indent, pos, max) + FILE *file; + char *sep; + char *type; + char *name; + char *indent; + int pos; + int max; +{ + if (strlen (sep) + strlen (type) + strlen (name) + pos > max) + { + fprintf (file, indent); + return fprintf (file, "%s%s", type, name); + } + return pos + fprintf (file, "%s%s%s", sep, type, name); +} + +static struct { char *name; int value; } m_options[] = TARGET_SWITCHES; + +static void +output_options (file, f_options, f_len, W_options, W_len, + pos, max, sep, indent, term) + FILE *file; + struct option *f_options; + struct option *W_options; + int f_len, W_len; + int pos; + int max; + char *indent; + char *term; +{ + register int j; + + if (optimize) + pos = output_option (file, sep, "-O", "", indent, pos, max); + if (write_symbols != NO_DEBUG) + pos = output_option (file, sep, "-g", "", indent, pos, max); +/* if (flag_traditional) + pos = output_option (file, sep, "-traditional", "", indent, pos, max);*/ + if (profile_flag) + pos = output_option (file, sep, "-p", "", indent, pos, max); + if (profile_block_flag) + pos = output_option (file, sep, "-a", "", indent, pos, max); + + for (j = 0; j < f_len; j++) + if (*f_options[j].variable == f_options[j].on_value) + pos = output_option (file, sep, "-f", f_options[j].string, + indent, pos, max); + + for (j = 0; j < W_len; j++) + if (*W_options[j].variable == W_options[j].on_value) + pos = output_option (file, sep, "-W", W_options[j].string, + indent, pos, max); + + for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++) + if (m_options[j].name[0] != '\0' + && m_options[j].value > 0 + && ((m_options[j].value & target_flags) + == m_options[j].value)) + pos = output_option (file, sep, "-m", m_options[j].name, + indent, pos, max); + + pos = output_option (file, sep, "-mcpu=", ix86_cpu_string, indent, pos, max); + pos = output_option (file, sep, "-march=", ix86_arch_string, indent, pos, max); + fprintf (file, term); +} + +/* Output to FILE the start of the assembler file. */ + +void +output_file_start (file, f_options, f_len, W_options, W_len) + FILE *file; + struct option *f_options; + struct option *W_options; + int f_len, W_len; +{ + register int pos; + + output_file_directive (file, main_input_filename); + fprintf (file, "\t.version\t\"01.01\"\n"); \ + /* Switch to the data section so that the coffsem symbol and the + gcc2_compiled. symbol aren't in the text section. */ + data_section (); + + pos = fprintf (file, "\n// cc1 (%s) arguments:", VERSION_STRING); + output_options (file, f_options, f_len, W_options, W_len, + pos, 75, " ", "\n// ", "\n\n"); + +#ifdef TARGET_IDENTIFY_REVISION + if (TARGET_IDENTIFY_REVISION) + { + char indent[256]; + + time_t now = time ((time_t *)0); + sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename); + fprintf (file, indent+3); + pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now)); + output_options (file, f_options, f_len, W_options, W_len, + pos, 150 - strlen (indent), " ", indent, "]\"\n\n"); + } +#endif /* TARGET_IDENTIFY_REVISION */ +} + +#ifndef CROSS_COMPILE +#if defined (_abort_aux) +/* Debugging aid to be registered via `atexit'. See the definition + of abort in dgux.h. */ +void +abort_aux () +{ + extern int insn_; + extern char * file_; + extern int line_; + static int done; + rtx line_note; + + if (done++) + return; + if (file_ || line_) + { + if (write_symbols != NO_DEBUG) + { + for (line_note = (rtx) insn_ ; line_note != 0 ; line_note = PREV_INSN (line_note)) + if (GET_CODE (line_note) == NOTE && NOTE_LINE_NUMBER (line_note) > 0) + break; + if (line_note != 0) + { + error_with_file_and_line (NOTE_SOURCE_FILE (line_note), + NOTE_LINE_NUMBER (line_note), + "Internal gcc abort from %s:%d", + file_ ? file_ : "<nofile>", line_); + if (insn_ && file_ && strcmp (file_, "toplev.c")) + { + error_with_file_and_line (NOTE_SOURCE_FILE (line_note), + NOTE_LINE_NUMBER (line_note), + "The local variable `insn' has the value:", 0); + debug_rtx ((rtx) insn_); + } + } + } + if (write_symbols == NO_DEBUG || line_note == 0) + { + error ("Internal gcc abort from %s:%d", + file_ ? file_ : "<nofile>", line_); + if (insn_ && file_ && strcmp (file_, "toplev.c")) + { + error ("The local variable `insn' has the value:", 0); + debug_rtx ((rtx) insn_); + } + } + } +} +#endif +#endif + + diff --git a/gnu/egcs/gcc/config/i386/dgux.h b/gnu/egcs/gcc/config/i386/dgux.h new file mode 100644 index 00000000000..54839176140 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/dgux.h @@ -0,0 +1,248 @@ +/* Target definitions for GNU compiler for Intel 80x86 running DG/ux + Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Currently maintained by gcc@dg-rtp.dg.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. */ + +/* for now, we are just like the sysv4 version with a + few hacks +*/ + +#include "i386/sysv4.h" + +#ifndef VERSION_INFO2 +#define VERSION_INFO2 "$Revision: 1.1.1.1 $" +#endif + +#ifndef VERSION_STRING +#define VERSION_STRING version_string +#endif + +/* Identify the compiler. */ +/* TARGET_VERSION used by toplev.c VERSION_STRING used by -midentify-revision */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (%s%s, %s)", \ + VERSION_INFO1, VERSION_INFO2, __DATE__) +#undef VERSION_INFO1 +#define VERSION_INFO1 "ix86 DG/ux, " + +/* Augment TARGET_SWITCHES with the MXDB options. */ +#define MASK_STANDARD 0x40000000 /* Retain standard information */ +#define MASK_NOLEGEND 0x20000000 /* Discard legend information */ +#define MASK_EXTERNAL_LEGEND 0x10000000 /* Make external legends */ +#define MASK_IDENTIFY_REVISION 0x08000000 /* Emit 'ident' to .s */ +#define MASK_WARN_PASS_STRUCT 0x04000000 /* Warn when structures are passed */ + +#define TARGET_STANDARD (target_flags & MASK_STANDARD) +#define TARGET_NOLEGEND (target_flags & MASK_NOLEGEND) +#define TARGET_EXTERNAL_LEGEND (target_flags & MASK_EXTERNAL_LEGEND) +#define TARGET_IDENTIFY_REVISION (target_flags & MASK_IDENTIFY_REVISION) +#define TARGET_WARN_PASS_STRUCT (target_flags & MASK_WARN_PASS_STRUCT) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "standard", MASK_STANDARD, "Retain standard MXDB information" }, \ + { "legend", -MASK_NOLEGEND, "Retain legend information" }, \ + { "no-legend", MASK_NOLEGEND, "" }, \ + { "external-legend", MASK_EXTERNAL_LEGEND, "Generate external legend information" }, \ + { "identify-revision", MASK_IDENTIFY_REVISION, "Emit identifying info in .s file" }, \ + { "warn-passed-structs", MASK_WARN_PASS_STRUCT, "Warn when a function arg is a structure" }, + +#undef DWARF_DEBUGGING_INFO +#define DWARF_DEBUGGING_INFO + +/* + allow -gstabs so that those who have gnu-as installed + can debug c++ programs. +*/ +#undef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO + +#define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG + +/* Override svr[34].h. */ +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + output_file_start (FILE, f_options, sizeof f_options / sizeof f_options[0], \ + W_options, sizeof W_options / sizeof W_options[0]) + +/* ix86 abi specified type for wchar_t */ + +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + + +/* Some machines may desire to change what optimizations are performed for + various optimization levels. This macro, if defined, is executed once + just after the optimization level is determined and before the remainder + of the command options have been parsed. Values set in this macro are + used as the default values for the other command line options. + + LEVEL is the optimization level specified; 2 if -O2 is specified, + 1 if -O is specified, and 0 if neither is specified. */ + +/* This macro used to store 0 in flag_signed_bitfields. + Not only is that misuse of this macro; the whole idea is wrong. + + The GNU C dialect makes bitfields signed by default, + regardless of machine type. Making any machine inconsistent in this + regard is bad for portability. + + I chose to make bitfields signed by default because this is consistent + with the way ordinary variables are handled: `int' equals `signed int'. + If there is a good reason to prefer making bitfields unsigned by default, + it cannot have anything to do with the choice of machine. + If the reason is good enough, we should change the convention for all machines. + + -- rms, 20 July 1991. */ + +/* + this really should go into dgux-local.h +*/ + +#undef OPTIMIZATION_OPTIONS +#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) \ + do { \ + extern int flag_signed_bitfields; \ + flag_signed_bitfields = 0; \ + optimization_options (LEVEL,SIZE); \ + } while (0) + + +/* The normal location of the `ld' and `as' programs */ + +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/usr/bin/" + +/* The normal location of the various *crt*.o files is the */ + +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/usr/lib/" + +/* Macros to be automatically defined. + __CLASSIFY_TYPE__ is used in the <varargs.h> and <stdarg.h> header + files with DG/UX revision 5.40 and later. This allows GNU CC to + operate without installing the header files. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -D__ix86 -Dunix -DDGUX -D__CLASSIFY_TYPE__=2\ + -Asystem(unix) -Asystem(svr4) -Acpu(i386) -Amachine(i386)" + + /* + If not -ansi, -traditional, or restricting include files to one + specific source target, specify full DG/UX features. + */ +#undef CPP_SPEC +#define CPP_SPEC "%{!ansi:%{!traditional:-D__OPEN_NAMESPACE__}}" + +/* Assembler support (legends for mxdb). */ +#undef ASM_SPEC +#define ASM_SPEC "\ +%{mno-legend:%{mstandard:-Wc,off}}\ +%{g:%{!mno-legend:-Wc,-fix-bb,-s\"%i\"\ +%{traditional:,-lc}%{!traditional:,-lansi-c}\ +%{mstandard:,-keep-std}\ +%{mexternal-legend:,-external}}}" + +/* Override svr4.h. */ + +/* hassey 3/12/94 keep svr4 ASM_FINAL_SPEC allows -pipe to work */ + +/* Linker and library spec's. + -static, -shared, -symbolic, -h* and -z* access AT&T V.4 link options. + -svr4 instructs gcc to place /usr/lib/values-X[cat].o on link the line. + The absence of -msvr4 indicates linking done in a COFF environment and + adds the link script to the link line. In all environments, the first + and last objects are crtbegin.o and crtend.o. + When the -G link option is used (-shared and -symbolic) a final link is + not being done. */ + +#undef LIB_SPEC +#define LIB_SPEC \ +"%{!shared:%{!symbolic:-lc}}" + +#undef LINK_SPEC +#define LINK_SPEC "%{z*} %{h*} %{v:-V} \ + %{static:-dn -Bstatic} \ + %{shared:-G -dy} \ + %{symbolic:-Bsymbolic -G -dy} \ + %{pg:-L/usr/lib/libp}%{p:-L/usr/lib/libp}" + +#ifdef CROSS_COMPILE + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{!shared:%{!symbolic:%{pg:gcrt1.o%s} \ + %{!pg:%{p:mcrt1.o%s} \ + %{!p:crt1.o%s}}}} \ + %{pg:gcrti.o%s}%{!pg:crti.o%s} \ + crtbegin.o%s \ + %{ansi:values-Xc.o%s} \ + %{!ansi:%{traditional:values-Xt.o%s} \ + %{!traditional:values-Xa.o%s}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:crtn.o%s}" + +#else + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{!shared:%{!symbolic:%{pg:gcrt1.o%s} \ + %{!pg:%{p:/lib/mcrt1.o%s} \ + %{!p:/lib/crt1.o%s}}} \ + %{pg:gcrti.o%s}%{!pg:/lib/crti.o%s}} \ + crtbegin.o%s \ + %{ansi:/lib/values-Xc.o%s} \ + %{!ansi:%{traditional:/lib/values-Xt.o%s} \ + %{!traditional:/lib/values-Xa.o%s}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:/lib/crtn.o}" + +#endif /* CROSS_COMPILE */ + +/* The maximum alignment which the object file format can support. + page alignment would seem to be enough */ +#undef MAX_OFILE_ALIGNMENT +#define MAX_OFILE_ALIGNMENT 0x1000 + +/* Must use data section for relocatable constants when pic. */ +#undef SELECT_RTX_SECTION +#define SELECT_RTX_SECTION(MODE,RTX) \ +{ \ + if (flag_pic && symbolic_operand (RTX)) \ + data_section (); \ + else \ + const_section (); \ +} + +/* This supplements FUNCTION_ARG's definition in i386.h to check + TARGET_WARN_PASS_STRUCT */ + +#undef FUNCTION_ARG +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +((((MODE) == BLKmode && TARGET_WARN_PASS_STRUCT) ? \ + warning ("argument is a structure"),0 : 0), \ + (function_arg (&CUM, MODE, TYPE, NAMED))) + +/* Add .align 1 to avoid .backalign bug in assembler */ +#undef CONST_SECTION_ASM_OP +#define CONST_SECTION_ASM_OP ".section\t.rodata\n\t.align 1" diff --git a/gnu/egcs/gcc/config/i386/djgpp-rtems.h b/gnu/egcs/gcc/config/i386/djgpp-rtems.h new file mode 100644 index 00000000000..b355cc5796a --- /dev/null +++ b/gnu/egcs/gcc/config/i386/djgpp-rtems.h @@ -0,0 +1,41 @@ +/* Configuration for an i386 running RTEMS on top of MS-DOS with + DJGPP v2.x. + + Copyright (C) 1996,1999 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 "i386/djgpp.h" + +/* Specify predefined symbols in preprocessor. */ + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif +#define CPP_PREDEFINES "-Dunix -Di386 -DGO32 -DDJGPP=2 -DMSDOS \ + -Asystem(unix) -Asystem(msdos) -Acpu(i386) -Amachine(i386) \ + -Asystem(rtems)" + +/* Generate calls to memcpy, memcmp and memset. */ +#ifndef TARGET_MEM_FUNCTIONS +#define TARGET_MEM_FUNCTIONS +#endif + +/* end of i386/djgpp-rtems.h */ + diff --git a/gnu/egcs/gcc/config/i386/djgpp.h b/gnu/egcs/gcc/config/i386/djgpp.h new file mode 100644 index 00000000000..6cee75bc837 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/djgpp.h @@ -0,0 +1,153 @@ +/* Configuration for an i386 running MS-DOS with DJGPP. + Copyright (C) 1997, 1998, 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. */ + + +#include "dbxcoff.h" + +/* Don't assume anything about the header files. */ +#define NO_IMPLICIT_EXTERN_C + +#define HANDLE_SYSV_PRAGMA + +/* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop). */ +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +#define YES_UNDERSCORES + +#include "i386/gas.h" + +/* Enable alias attribute support. */ +#ifndef SET_ASM_OP +#define SET_ASM_OP "\t.set" +#endif + +/* Search for as.exe and ld.exe in DJGPP's binary directory. */ +#define MD_EXEC_PREFIX "$DJDIR/bin/" + +/* Correctly handle absolute filename detection in cp/xref.c */ +#define FILE_NAME_ABSOLUTE_P(NAME) \ + (((NAME)[0] == '/') || ((NAME)[0] == '\\') || \ + (((NAME)[0] >= 'A') && ((NAME)[0] <= 'z') && ((NAME)[1] == ':'))) + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif +#define CPP_PREDEFINES "-Dunix -Di386 -DGO32 -DDJGPP=2 -DMSDOS \ + -Asystem(unix) -Asystem(msdos) -Acpu(i386) -Amachine(i386)" + +/* We need to override link_command_spec in gcc.c so support -Tdjgpp.djl. + This cannot be done in LINK_SPECS as that LINK_SPECS is processed + before library search directories are known by the linker. + This avoids problems when specs file is not available. An alternate way, + suggested by Robert Hoehne, is to use SUBTARGET_EXTRA_SPECS instead. +*/ + +#undef LINK_COMMAND_SPEC +#define LINK_COMMAND_SPEC \ +"%{!fsyntax-only: \ +%{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \ +\t%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\ +\t%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ +\t%{static:} %{L*} %D %o\ +\t%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\ +\t%{!A:%{!nostdlib:%{!nostartfiles:%E}}}\ +\t-Tdjgpp.djl %{T*}}}}}}}\n\ +%{!c:%{!M:%{!MM:%{!E:%{!S:stubify %{v} %{o*:%*} %{!o*:a.out} }}}}}" + +/* Make sure that gcc will not look for .h files in /usr/local/include + unless user explicitly requests it. */ +#undef LOCAL_INCLUDE_DIR + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctor, in_dtor + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTOR_SECTION_FUNCTION \ + DTOR_SECTION_FUNCTION + +#define CTOR_SECTION_FUNCTION \ +void \ +ctor_section () \ +{ \ + if (in_section != in_ctor) \ + { \ + fprintf (asm_out_file, "\t.section .ctor\n"); \ + in_section = in_ctor; \ + } \ +} + +#define DTOR_SECTION_FUNCTION \ +void \ +dtor_section () \ +{ \ + if (in_section != in_dtor) \ + { \ + fprintf (asm_out_file, "\t.section .dtor\n"); \ + in_section = in_dtor; \ + } \ +} + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Allow (eg) __attribute__((section "locked")) to work */ +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC)\ + do { \ + fprintf (FILE, "\t.section %s\n", NAME); \ + } while (0) + +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + output_file_directive (FILE, main_input_filename); \ + } 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.p2align %d\n", LOG) + +/* djgpp has atexit (). */ +#undef HAVE_ATEXIT +#define HAVE_ATEXIT + +/* djgpp automatically calls its own version of __main, so don't define one + in libgcc, nor call one in main(). */ +#define HAS_INIT_SECTION diff --git a/gnu/egcs/gcc/config/i386/freebsd-elf.h b/gnu/egcs/gcc/config/i386/freebsd-elf.h new file mode 100644 index 00000000000..988f6a9842f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/freebsd-elf.h @@ -0,0 +1,206 @@ +/* Definitions for Intel 386 running FreeBSD with ELF format + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Eric Youngdale. + Modified for stabs-in-ELF by H.J. Lu. + Adapted from GNU/Linux version by John Polstra. + +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. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)"); + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. */ +/* On FreeBSD, we do not. */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* This gets defined in tm.h->linux.h->svr4.h, and keeps us from using + libraries compiled with the native cc, so undef it. */ +#undef NO_DOLLAR_IN_LABEL + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +/* Copy this from the svr4 specifications... */ +/* Define the register numbers to be used in Dwarf debugging information. + The SVR4 reference port C compiler uses the following register numbers + in its Dwarf output code: + 0 for %eax (gnu regno = 0) + 1 for %ecx (gnu regno = 2) + 2 for %edx (gnu regno = 1) + 3 for %ebx (gnu regno = 3) + 4 for %esp (gnu regno = 7) + 5 for %ebp (gnu regno = 6) + 6 for %esi (gnu regno = 4) + 7 for %edi (gnu regno = 5) + The following three DWARF register numbers are never generated by + the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 + believes these numbers have these meanings. + 8 for %eip (no gnu equivalent) + 9 for %eflags (no gnu equivalent) + 10 for %trapno (no gnu equivalent) + It is not at all clear how we should number the FP stack registers + for the x86 architecture. If the version of SDB on x86/svr4 were + a bit less brain dead with respect to floating-point then we would + have a precedent to follow with respect to DWARF register numbers + for x86 FP registers, but the SDB on x86/svr4 is so completely + broken with respect to FP registers that it is hardly worth thinking + of it as something to strive for compatibility with. + The version of x86/svr4 SDB I have at the moment does (partially) + seem to believe that DWARF register number 11 is associated with + the x86 register %st(0), but that's about all. Higher DWARF + register numbers don't seem to be associated with anything in + particular, and even for DWARF regno 11, SDB only seems to under- + stand that it should say that a variable lives in %st(0) (when + asked via an `=' command) if we said it was in DWARF regno 11, + but SDB still prints garbage when asked for the value of the + variable in question (via a `/' command). + (Also note that the labels SDB prints for various FP stack regs + when doing an `x' command are all wrong.) + Note that these problems generally don't affect the native SVR4 + C compiler because it doesn't allow the use of -O with -g and + because when it is *not* optimizing, it allocates a memory + location for each floating-point variable, and the memory + location is what gets described in the DWARF AT_location + attribute for the variable in question. + Regardless of the severe mental illness of the x86/svr4 SDB, we + do something sensible here and we use the following DWARF + register numbers. Note that these are all stack-top-relative + numbers. + 11 for %st(0) (gnu regno = 8) + 12 for %st(1) (gnu regno = 9) + 13 for %st(2) (gnu regno = 10) + 14 for %st(3) (gnu regno = 11) + 15 for %st(4) (gnu regno = 12) + 16 for %st(5) (gnu regno = 13) + 17 for %st(6) (gnu regno = 14) + 18 for %st(7) (gnu regno = 15) +*/ +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -Dunix -D__ELF__ -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}" + +#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 C library, please add + * -lc_p or -ggdb to LDFLAGS at the link time, respectively. + */ +#define LIB_SPEC \ + "%{!shared: %{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} \ + %{!ggdb:-lc} %{ggdb:-lg}}" +#else +#define LIB_SPEC \ + "%{!shared: \ + %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \ + %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}" +#endif + +/* Provide a LINK_SPEC appropriate for FreeBSD. 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. */ + +#undef LINK_SPEC +#define LINK_SPEC "-m elf_i386 %{shared:-shared} \ + %{!shared: \ + %{!ibcs: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \ + %{static:-static}}}" + +/* Get perform_* macros to build libgcc.a. */ + +/* A C statement to output to the stdio stream FILE an assembler + command to advance the location counter to a multiple of 1<<LOG + bytes if it is within MAX_SKIP bytes. + + This is used to align code labels according to Intel recommendations. */ + +#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN +#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \ + if ((LOG) != 0) {\ + if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + } +#endif diff --git a/gnu/egcs/gcc/config/i386/freebsd.h b/gnu/egcs/gcc/config/i386/freebsd.h new file mode 100644 index 00000000000..52302222ae3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/freebsd.h @@ -0,0 +1,274 @@ +/* Definitions of target machine for GNU compiler for Intel 80386 + running FreeBSD. + Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc. + Contributed by Poul-Henning Kamp <phk@login.dkuug.dk> + +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 is tested by i386gas.h. */ +#define YES_UNDERSCORES + +/* Don't assume anything about the header files. */ +#define NO_IMPLICIT_EXTERN_C + +#include "i386/gstabs.h" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +/* This goes away when the math-emulator is fixed */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)" + +/* Like the default, except no -lg. */ +#define LIB_SPEC "%{!shared:%{!pg:-lc}%{pg:-lc_p}}" + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +#define HAVE_ATEXIT + +/* Override the default comment-starter of "/". */ + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/* FreeBSD using a.out does not support DWARF2 unwinding mechanisms. */ +#define DWARF2_UNWIND_INFO 0 + +/* The following macros are stolen from i386v4.h */ +/* These have to be defined to get PIC code correct */ + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Don't default to pcc-struct-return, because in FreeBSD we prefer the + superior nature of the older gcc way. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* Ensure we the configuration knows our system correctly so we can link with + libraries compiled with the native cc. */ +#undef NO_DOLLAR_IN_LABEL + +/* i386 freebsd still uses old binutils that don't insert nops by default + when the .align directive demands to insert extra space in the text + segment. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) + +/* Profiling routines, partially copied from i386/osfrose.h. */ + +/* Redefine this to use %eax instead of %edx. */ +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%eax\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%eax\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +/* + * Some imports from svr4.h in support of shared libraries. + * Currently, we need the DECLARE_OBJECT_SIZE stuff. + */ + +/* Define the strings used for the special svr4 .type and .size directives. + These strings generally do not vary from one system running svr4 to + another, but if a given system (e.g. m88k running svr) needs to use + different pseudo-op names for these, they may be overridden in the + file which includes this one. */ + +#define TYPE_ASM_OP ".type" +#define SIZE_ASM_OP ".size" + +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ + +#define TYPE_OPERAND_FMT "@%s" + +/* Write the extra assembler code needed to declare a function's result. + Most svr4 assemblers don't require any special declaration of the + result value, but there are exceptions. */ + +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +/* These macros generate the special .type and .size directives which + are used to set the corresponding fields of the linker symbol table + entries in an ELF object file under SVR4. These macros also output + the starting labels for the relevant functions/objects. */ + +/* Write the extra assembler code needed to declare a function properly. + Some svr4 assemblers need to also have something extra said about the + function's return value. We allow for that here. */ + +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', FILE); \ + ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } while (0) + +/* Write the extra assembler code needed to declare an object properly. */ + +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do { \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } while (0) + +/* Output the size directive for a decl in rest_of_decl_compilation + in the case where we did not do so before the initializer. + Once we find the error_mark_node, we know that the value of + size_directive_output was set + by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ + +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ +do { \ + char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\ + } \ + } while (0) + + +/* This is how to declare the size of a function. */ + +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } \ + } while (0) + +#define ASM_SPEC " %| %{fpic:-k} %{fPIC:-k}" +#define LINK_SPEC \ + "%{p:%e`-p' not supported; use `-pg' and gprof(1)} \ + %{shared:-Bshareable} \ + %{!shared:%{!nostdlib:%{!r:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} \ + %{pg:-Bstatic} %{Z}} \ + %{assert*} %{R*}" + +#define STARTFILE_SPEC \ + "%{shared:c++rt0.o%s} \ + %{!shared:%{pg:gcrt0.o%s}%{!pg:%{static:scrt0.o%s}%{!static:crt0.o%s}}}" + +/* This is defined when gcc is compiled in the BSD-directory-tree, and must + * make up for the gap to all the stuff done in the GNU-makefiles. + */ + +#ifdef FREEBSD_NATIVE + +#define INCLUDE_DEFAULTS { \ + { "/usr/include", 0, 0, 0 }, \ + { "/usr/include/g++", "G++", 1, 1 }, \ + { 0, 0, 0, 0} \ + } + +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/usr/libexec/" + +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/lib" + +#if 0 /* This is very wrong!!! */ +#define DEFAULT_TARGET_MACHINE "i386-unknown-freebsd_1.0" +#define GPLUSPLUS_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include" +#define TOOL_INCLUDE_DIR "/usr/local/i386-unknown-freebsd_1.0/include" +#define GCC_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include" +#endif + +#endif /* FREEBSD_NATIVE */ diff --git a/gnu/egcs/gcc/config/i386/gas.h b/gnu/egcs/gcc/config/i386/gas.h new file mode 100644 index 00000000000..4ce1891f2c5 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/gas.h @@ -0,0 +1,162 @@ +/* Definitions for Intel 386 using GAS. + Copyright (C) 1988, 1993, 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. */ + +/* Note that i386/seq-gas.h is a GAS configuration that does not use this + file. */ + +#include "i386/i386.h" + +#ifndef YES_UNDERSCORES +/* Define this now, because i386/bsd.h tests it. */ +#define NO_UNDERSCORES +#endif + +/* Use the bsd assembler syntax. */ +/* we need to do this because gas is really a bsd style assembler, + * and so doesn't work well this these att-isms: + * + * ASM_OUTPUT_SKIP is .set .,.+N, which isn't implemented in gas + * ASM_OUTPUT_LOCAL is done with .set .,.+N, but that can't be + * used to define bss static space + * + * Next is the question of whether to uses underscores. RMS didn't + * like this idea at first, but since it is now obvious that we + * need this separate tm file for use with gas, at least to get + * dbx debugging info, I think we should also switch to underscores. + * We can keep i386v for real att style output, and the few + * people who want both form will have to compile twice. + */ + +#include "i386/bsd.h" + +/* these come from i386/bsd.h, but are specific to sequent */ +#undef DBX_NO_XREFS +#undef DBX_CONTIN_LENGTH + +/* Ask for COFF symbols. */ + +#define SDB_DEBUGGING_INFO + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix" +#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE}" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* In the past there was confusion as to what the argument to .align was + in GAS. For the last several years the rule has been this: for a.out + file formats that argument is LOG, and for all other file formats the + argument is 1<<LOG. + + However, GAS now has .p2align and .balign pseudo-ops so to remove any + doubt or guess work, and since this file is used for both a.out and other + file formats, we use one of them. */ + +#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.balign %d\n", 1<<(LOG)) +#endif + +/* A C statement to output to the stdio stream FILE an assembler + command to advance the location counter to a multiple of 1<<LOG + bytes if it is within MAX_SKIP bytes. + + This is used to align code labels according to Intel recommendations. */ + +#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN +# define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \ + if ((LOG) != 0) {\ + if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + } +#endif + +/* A C statement or statements which output an assembler instruction + opcode to the stdio stream STREAM. The macro-operand PTR is a + variable of type `char *' which points to the opcode name in its + "internal" form--the form that is written in the machine description. + + GAS version 1.38.1 doesn't understand the `repz' opcode mnemonic. + So use `repe' instead. */ + +#define ASM_OUTPUT_OPCODE(STREAM, PTR) \ +{ \ + if ((PTR)[0] == 'r' \ + && (PTR)[1] == 'e' \ + && (PTR)[2] == 'p') \ + { \ + if ((PTR)[3] == 'z') \ + { \ + fprintf (STREAM, "repe"); \ + (PTR) += 4; \ + } \ + else if ((PTR)[3] == 'n' && (PTR)[4] == 'z') \ + { \ + fprintf (STREAM, "repne"); \ + (PTR) += 5; \ + } \ + } \ +} + +/* Define macro used to output shift-double opcodes when the shift + count is in %cl. Some assemblers require %cl as an argument; + some don't. + + GAS requires the %cl argument, so override i386/unix.h. */ + +#undef SHIFT_DOUBLE_OMITS_COUNT +#define SHIFT_DOUBLE_OMITS_COUNT 0 + +/* Print opcodes the way that GAS expects them. */ +#define GAS_MNEMONICS 1 + +#ifdef NO_UNDERSCORES /* If user-symbols don't have underscores, + then it must take more than `L' to identify + a label that should be ignored. */ + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + +/* 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) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +#endif /* NO_UNDERSCORES */ diff --git a/gnu/egcs/gcc/config/i386/gmon-sol2.c b/gnu/egcs/gcc/config/i386/gmon-sol2.c new file mode 100644 index 00000000000..35ac1c9abb7 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/gmon-sol2.c @@ -0,0 +1,409 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is a modified gmon.c by J.W.Hawtin <oolon@ankh.org>, + * 14/8/96 based on the original gmon.c in GCC and the hacked version + * solaris 2 sparc version (config/sparc/gmon-sol.c) by Mark Eichin. To do + * process profiling on solaris 2.X X86 + * + * It must be used in conjunction with sol2-gc1.asm, which is used to start + * and stop process monitoring. + * + * Differences. + * + * On Solaris 2 _mcount is called by library functions not mcount, so support + * has been added for both. + * + * Also the prototype for profil() is different + * + * Solaris 2 does not seem to have char *minbrk whcih allows the setting of + * the minimum SBRK region so this code has been removed and lets pray malloc + * does not mess it up. + * + * Notes + * + * This code could easily be integrated with the original gmon.c and perhaps + * should be. + */ + +#ifndef lint +static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91"; +#endif /* not lint */ + +#if 0 +#include <unistd.h> + +#endif +#ifdef DEBUG +#include <stdio.h> +#endif + +#if 0 +#include "i386/gmon.h" +#else + +struct phdr { + char *lpc; + char *hpc; + int ncnt; +}; + + +#define HISTFRACTION 2 +#define HISTCOUNTER unsigned short +#define HASHFRACTION 1 +#define ARCDENSITY 2 +#define MINARCS 50 +#define BASEADDRESS 0x8000000 /* On Solaris 2 X86 all executables start here + and not at 0 */ + +struct tostruct { + char *selfpc; + long count; + unsigned short link; +}; +struct rawarc { + unsigned long raw_frompc; + unsigned long raw_selfpc; + long raw_count; +}; +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) +#endif + +/* char *minbrk; */ + +#ifdef __alpha +extern char *sbrk (); +#endif + + /* + * froms is actually a bunch of unsigned shorts indexing tos + */ +static int profiling = 3; +static unsigned short *froms; +static struct tostruct *tos = 0; +static long tolimit = 0; +static char *s_lowpc = 0; +static char *s_highpc = 0; +static unsigned long s_textsize = 0; + +static int ssiz; +static char *sbuf; +static int s_scale; + /* see profil(2) where this is describe (incorrectly) */ +#define SCALE_1_TO_1 0x10000L + +#define MSG "No space for profiling buffer(s)\n" + +extern int errno; + +monstartup(lowpc, highpc) + char *lowpc; + char *highpc; +{ + int monsize; + char *buffer; + register int o; + + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. + */ + lowpc = (char *) + ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); + s_lowpc = lowpc; + highpc = (char *) + ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); + s_highpc = highpc; + s_textsize = highpc - lowpc; + monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); + buffer = (char *) sbrk( monsize ); + if ( buffer == (char *) -1 ) { + write( 2 , MSG , sizeof(MSG) ); + return; + } + froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); + if ( froms == (unsigned short *) -1 ) { + write( 2 , MSG , sizeof(MSG) ); + froms = 0; + return; + } + tolimit = s_textsize * ARCDENSITY / 100; + if ( tolimit < MINARCS ) { + tolimit = MINARCS; + } else if ( tolimit > 65534 ) { + tolimit = 65534; + } + tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); + if ( tos == (struct tostruct *) -1 ) { + write( 2 , MSG , sizeof(MSG) ); + froms = 0; + tos = 0; + return; + } +/* minbrk = (char *) sbrk(0);*/ + tos[0].link = 0; + sbuf = buffer; + ssiz = monsize; + ( (struct phdr *) buffer ) -> lpc = lowpc; + ( (struct phdr *) buffer ) -> hpc = highpc; + ( (struct phdr *) buffer ) -> ncnt = ssiz; + monsize -= sizeof(struct phdr); + if ( monsize <= 0 ) + return; + o = highpc - lowpc; + if( monsize < o ) +#ifndef hp300 + s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; +#else /* avoid floating point */ + { + int quot = o / monsize; + + if (quot >= 0x10000) + s_scale = 1; + else if (quot >= 0x100) + s_scale = 0x10000 / quot; + else if (o >= 0x800000) + s_scale = 0x1000000 / (o / (monsize >> 8)); + else + s_scale = 0x1000000 / ((o << 8) / monsize); + } +#endif + else + s_scale = SCALE_1_TO_1; + moncontrol(1); +} + +_mcleanup() +{ + int fd; + int fromindex; + int endfrom; + char *frompc; + int toindex; + struct rawarc rawarc; + + moncontrol(0); + fd = creat( "gmon.out" , 0666 ); + if ( fd < 0 ) { + perror( "mcount: gmon.out" ); + return; + } +# ifdef DEBUG + fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); +# endif DEBUG + + write( fd , sbuf , ssiz ); + endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); + for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { + if ( froms[fromindex] == 0 ) { + continue; + } + frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); + for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { +# ifdef DEBUG + fprintf( stderr , + "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , + frompc , tos[toindex].selfpc , tos[toindex].count ); +# endif DEBUG + rawarc.raw_frompc = (unsigned long) frompc; + rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; + rawarc.raw_count = tos[toindex].count; + write( fd , &rawarc , sizeof rawarc ); + } + } + close( fd ); +} + +/* Solaris 2 libraries use _mcount. */ +asm(".globl _mcount; _mcount: jmp internal_mcount"); +/* This is for compatibility with old versions of gcc which used mcount. */ +asm(".globl mcount; mcount: jmp internal_mcount"); + +internal_mcount() +{ + register char *selfpc; + register unsigned short *frompcindex; + register struct tostruct *top; + register struct tostruct *prevtop; + register long toindex; + static char already_setup; + + /* + * find the return address for mcount, + * and the return address for mcount's caller. + */ + + /* selfpc = pc pushed by mcount call. + This identifies the function that was just entered. */ + selfpc = (void *) __builtin_return_address (0); + /* frompcindex = pc in preceding frame. + This identifies the caller of the function just entered. */ + frompcindex = (void *) __builtin_return_address (1); + + if(!already_setup) { + extern etext(); + already_setup = 1; +/* monstartup(0, etext); */ + monstartup(0x08040000, etext); +#ifdef USE_ONEXIT + on_exit(_mcleanup, 0); +#else + atexit(_mcleanup); +#endif + } + /* + * check that we are profiling + * and that we aren't recursively invoked. + */ + if (profiling) { + goto out; + } + profiling++; + /* + * check that frompcindex is a reasonable pc value. + * for example: signal catchers get called from the stack, + * not from text space. too bad. + */ + frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); + if ((unsigned long)frompcindex > s_textsize) { + goto done; + } + frompcindex = + &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; + toindex = *frompcindex; + if (toindex == 0) { + /* + * first time traversing this arc + */ + toindex = ++tos[0].link; + if (toindex >= tolimit) { + goto overflow; + } + *frompcindex = toindex; + top = &tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + top = &tos[toindex]; + if (top->selfpc == selfpc) { + /* + * arc at front of chain; usual case. + */ + top->count++; + goto done; + } + /* + * have to go looking down chain for it. + * top points to what we are looking at, + * prevtop points to previous top. + * we know it is not at the head of the chain. + */ + for (; /* goto done */; ) { + if (top->link == 0) { + /* + * top is end of the chain and none of the chain + * had top->selfpc == selfpc. + * so we allocate a new tostruct + * and link it to the head of the chain. + */ + toindex = ++tos[0].link; + if (toindex >= tolimit) { + goto overflow; + } + top = &tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + /* + * otherwise, check the next arc on the chain. + */ + prevtop = top; + top = &tos[top->link]; + if (top->selfpc == selfpc) { + /* + * there it is. + * increment its count + * move it to the head of the chain. + */ + top->count++; + toindex = prevtop->link; + prevtop->link = top->link; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + + } +done: + profiling--; + /* and fall through */ +out: + return; /* normal return restores saved registers */ + +overflow: + profiling++; /* halt further profiling */ +# define TOLIMIT "mcount: tos overflow\n" + write(2, TOLIMIT, sizeof(TOLIMIT)); + goto out; +} + +/* + * Control profiling + * profiling is what mcount checks to see if + * all the data structures are ready. + */ +moncontrol(mode) + int mode; +{ + if (mode) + { + /* start */ + profil((unsigned short *)(sbuf + sizeof(struct phdr)), + ssiz - sizeof(struct phdr), + (int)s_lowpc, s_scale); + + profiling = 0; + } else { + /* stop */ + profil((unsigned short *)0, 0, 0, 0); + profiling = 3; + } +} diff --git a/gnu/egcs/gcc/config/i386/gnu.h b/gnu/egcs/gcc/config/i386/gnu.h new file mode 100644 index 00000000000..971a5f880c2 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/gnu.h @@ -0,0 +1,23 @@ +/* Configuration for an i386 running GNU with ELF as the target machine. */ + +/* This does it mostly for us. */ +#include <i386/linux.h> + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -Acpu(i386) -Amachine(i386) \ +-Dunix -Asystem(unix) -DMACH -Asystem(mach) -D__GNU__ -Asystem(gnu)" + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 GNU)"); + +#undef LINK_SPEC +#define LINK_SPEC "-m elf_i386 %{shared:-shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld.so}} \ + %{static:-static}}" + + +/* Get machine-independent configuration parameters for the GNU system. */ +#include <gnu.h> diff --git a/gnu/egcs/gcc/config/i386/gstabs.h b/gnu/egcs/gcc/config/i386/gstabs.h new file mode 100644 index 00000000000..5f0ae348f15 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/gstabs.h @@ -0,0 +1,9 @@ +#include "i386/gas.h" + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO diff --git a/gnu/egcs/gcc/config/i386/i386-aout.h b/gnu/egcs/gcc/config/i386/i386-aout.h new file mode 100644 index 00000000000..e4be8d5dd15 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386-aout.h @@ -0,0 +1,34 @@ +/* Definitions for "naked" Intel 386 using a.out (or coff encap'd + a.out) object format and stabs debugging info. + + 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. */ + + +/* This is tested by gas.h. */ +#define YES_UNDERSCORES + +#include "i386/gstabs.h" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386" + +/* end of i386-aout.h */ diff --git a/gnu/egcs/gcc/config/i386/i386-coff.h b/gnu/egcs/gcc/config/i386/i386-coff.h new file mode 100644 index 00000000000..2e00b7a8907 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386-coff.h @@ -0,0 +1,103 @@ +/* Definitions for "naked" Intel 386 using coff object format files + and coff debugging info. + + 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. */ + + +#include "i386/gas.h" +#include "dbxcoff.h" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386" + +/* We want to be able to get DBX debugging information via -gstabs. */ + +#undef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG + +/* 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) + + +/* end of i386-coff.h */ diff --git a/gnu/egcs/gcc/config/i386/i386-interix.h b/gnu/egcs/gcc/config/i386/i386-interix.h new file mode 100644 index 00000000000..8e9f44393cc --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386-interix.h @@ -0,0 +1,575 @@ +/* Target definitions for GNU compiler for Intel 80386 running Interix + Parts Copyright (C) 1991, 1999 Free Software Foundation, Inc. + + Parts: + by Douglas B. Rupp (drupp@cs.washington.edu). + by Ron Guilmette (rfg@netcom.com). + by Donn Terry (donn@softway.com). + by Mumit Khan (khan@xraylith.wisc.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 YES_UNDERSCORES + +/* YES_UNDERSCORES must preceed gas.h */ +#include <i386/gas.h> +/* The rest must follow. */ + +#define DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#define HANDLE_SYSV_PRAGMA +#undef HANDLE_PRAGMA_WEAK /* until the link format can handle it */ + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387 and needs stack probes + We also align doubles to 64-bits for MSVC default compatability */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE | \ + MASK_ALIGN_DOUBLE) + +#undef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT 2 /* 486 */ + +#define WCHAR_UNSIGNED 1 +#define WCHAR_TYPE_SIZE 16 +#define WCHAR_TYPE "short unsigned int" + +/* WinNT (and thus Interix) use unsigned int */ +#define SIZE_TYPE "unsigned int" + +#define ASM_LOAD_ADDR(loc, reg) " leal " #loc "," #reg "\n" + +/* For the sake of libgcc2.c, indicate target supports atexit. */ +#define HAVE_ATEXIT + +/* cpp handles __STDC__ */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES " \ + -D__INTERIX \ + -D__OPENNT \ + -D_M_IX86=300 -D_X86_=1 \ + -D__stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -Asystem(unix) -Asystem(interix) -Asystem(interix) -Acpu(i386) -Amachine(i386)" + +#undef CPP_SPEC +/* Write out the correct language type definition for the header files. + Unless we have assembler language, write out the symbols for C. + cpp_cpu is an Intel specific variant. See i386.h + mieee is an Alpha specific variant. Cross polination a bad idea. + */ +#define CPP_SPEC "\ +%{!.S: -D__LANGUAGE_C__ -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}} \ +%{.S: -D__LANGUAGE_ASSEMBLY__ -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \ +%{.cc: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \ +%{.cxx: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \ +%{.C: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \ +%{.m: -D__LANGUAGE_OBJECTIVE_C__ -D__LANGUAGE_OBJECTIVE_C} \ +-remap \ +%(cpp_cpu) \ +%{posix:-D_POSIX_SOURCE} \ +-idirafter %$INTERIX_ROOT/usr/include" + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 Interix)"); + +/* The global __fltused is necessary to cause the printf/scanf routines + for outputting/inputting floating point numbers to be loaded. Since this + is kind of hard to detect, we just do it all the time. */ + +#ifdef ASM_FILE_START +#undef ASM_FILE_START +#endif +#define ASM_FILE_START(FILE) \ + do { fprintf (FILE, "\t.file\t"); \ + output_quoted_string (FILE, dump_base_name); \ + fprintf (FILE, "\n"); \ + fprintf (FILE, ".global\t__fltused\n"); \ + } while (0) + +/* A table of bytes codes used by the ASM_OUTPUT_ASCII and + ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table + corresponds to a particular byte value [0..255]. For any + given byte value, if the value in the corresponding table + position is zero, the given character can be output directly. + If the table value is 1, the byte must be output as a \ooo + octal escape. If the tables value is anything else, then the + byte value should be output as a \ followed by the value + in the table. Note that we can use standard UN*X escape + sequences for many control characters, but we don't use + \a to represent BEL because some svr4 assemblers (e.g. on + the i386) don't know about that. Also, we don't use \v + since some versions of gas, such as 2.2 did not accept it. */ + +#define ESCAPES \ +"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\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\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\\\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\0\0\0\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" + +/* Some svr4 assemblers have a limit on the number of characters which + can appear in the operand of a .string directive. If your assembler + has such a limitation, you should define STRING_LIMIT to reflect that + limit. Note that at least some svr4 assemblers have a limit on the + actual number of bytes in the double-quoted string, and that they + count each character in an escape sequence as one byte. Thus, an + escape sequence like \377 would count as four bytes. + + If your target assembler doesn't support the .string directive, you + should define this to zero. +*/ + +#define STRING_LIMIT ((unsigned) 256) + +#define STRING_ASM_OP ".string" + +/* The routine used to output NUL terminated strings. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable, especially for targets like the i386 + (where the only alternative is to output character sequences as + comma separated lists of numbers). */ + +#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ + do \ + { \ + register unsigned char *_limited_str = (unsigned char *) (STR); \ + register unsigned ch; \ + fprintf ((FILE), "\t%s\t\"", STRING_ASM_OP); \ + for (; (ch = *_limited_str); _limited_str++) \ + { \ + register int escape = ESCAPES[ch]; \ + switch (escape) \ + { \ + case 0: \ + putc (ch, (FILE)); \ + break; \ + case 1: \ + fprintf ((FILE), "\\%03o", ch); \ + break; \ + default: \ + putc ('\\', (FILE)); \ + putc (escape, (FILE)); \ + break; \ + } \ + } \ + fprintf ((FILE), "\"\n"); \ + } \ + while (0) + +/* The routine used to output sequences of byte values. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable. Note that if we find subparts of the + character sequence which end with NUL (and which are shorter than + STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ + do \ + { \ + register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ + register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register unsigned bytes_in_chunk = 0; \ + for (; _ascii_bytes < limit; _ascii_bytes++) \ + { \ + register unsigned char *p; \ + if (bytes_in_chunk >= 64) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ + continue; \ + if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + { \ + if (bytes_in_chunk > 0) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \ + _ascii_bytes = p; \ + } \ + else \ + { \ + if (bytes_in_chunk == 0) \ + fprintf ((FILE), "\t.byte\t"); \ + else \ + fputc (',', (FILE)); \ + fprintf ((FILE), "0x%02x", *_ascii_bytes); \ + bytes_in_chunk += 5; \ + } \ + } \ + if (bytes_in_chunk > 0) \ + fprintf ((FILE), "\n"); \ + } \ + while (0) + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. + PE format differs on what PC-relative offsets look like (see + coff_i386_rtype_to_howto), and we need to compensate (by one word) here. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long __GLOBAL_OFFSET_TABLE_+[.-%s%d+4]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Emit code to check the stack when allocating more that 4000 + bytes in one go. */ + +#define CHECK_STACK_LIMIT 0x1000 + +/* the following are OSF linker (not gld) specific... we don't want them */ +#undef HAS_INIT_SECTION +#undef LD_INIT_SWITCH +#undef LD_FINI_SWITCH + + +/* The following are needed for C++, but also needed for profiling */ + +/* Support const sections and the ctors and dtors sections for g++. + Note that there appears to be two different ways to support const + sections at the moment. You can either #define the symbol + READONLY_DATA_SECTION (giving it some code which switches to the + readonly data section) or else you can #define the symbols + EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and + SELECT_RTX_SECTION. We do both here just to be on the safe side. */ + +#define USE_CONST_SECTION 1 + +#define CONST_SECTION_ASM_OP ".section\t.rdata,\"r\"" + +/* Define the pseudo-ops used to switch to the .ctors and .dtors sections. + + Note that we want to give these sections the SHF_WRITE attribute + because these sections will actually contain data (i.e. tables of + addresses of functions in the current root executable or shared library + file) and, in the case of a shared library, the relocatable addresses + will have to be properly resolved/relocated (and then written into) by + the dynamic linker when it actually attaches the given shared library + to the executing process. (Note that on SVR4, you may wish to use the + `-z text' option to the ELF linker, when building a shared library, as + an additional check that you are doing everything right. But if you do + use the `-z text' option when building a shared library, you will get + errors unless the .ctors and .dtors sections are marked as writable + via the SHF_WRITE attribute.) */ + +#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"x\"" +#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"x\"" + +/* A default list of other sections which we might be "in" at any given + time. For targets that use additional sections (e.g. .tdesc) you + should override this definition in the target-specific file which + includes this file. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_const, in_ctors, in_dtors + +/* A default list of extra section function definitions. For targets + that use additional sections (e.g. .tdesc) you should override this + definition in the target-specific file which includes this file. */ + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CONST_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION + +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION() const_section () + +extern void text_section (); + +#define CONST_SECTION_FUNCTION \ +void \ +const_section () \ +{ \ + if (!USE_CONST_SECTION) \ + text_section(); \ + else if (in_section != in_const) \ + { \ + fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \ + in_section = in_const; \ + } \ +} + +#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; \ + } \ +} + +#if 0 +/* Currently gas chokes on this; that's not too hard to fix, but there's + not a lot of impeteus to do it, either. If it is done, gas will have + to handle long section name escapes (which are defined in the COFF/PE + document as /nnn where nnn is a string table index). The benefit: + section attributes and -ffunction-sections, neither of which seem to + be critical. */ +/* gas may have been fixed? bfd was. */ + +/* Switch into a generic section. + This is currently only used to support section attributes. + + We make the section read-only and executable for a function decl, + read-only for a const data decl, and writable for a non-const data decl. */ +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME) \ + fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \ + (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \ + (DECL) && TREE_READONLY (DECL) ? "a" : "aw") +#endif + +#define INT_ASM_OP ".long" + +/* The MS compilers take alignment as a number of bytes, so we do as well */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.balign %d\n", 1<<(LOG)) + +/* 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) + +/* The linker will take care of this, and having them causes problems with + ld -r (specifically -rU). */ +#define CTOR_LISTS_DEFINED_EXTERNALLY 1 + +#define SET_ASM_OP ".set" +/* Output a definition (implements alias) */ +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ +do \ +{ \ + fprintf ((FILE), "\t%s\t", SET_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } \ +while (0) + +#define HOST_PTR_PRINTF "%p" +#define HOST_PTR_AS_INT unsigned long + +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define PCC_BITFIELD_TYPE_TEST TYPE_NATIVE(rec) +#define GROUP_BITFIELDS_BY_ALIGN TYPE_NATIVE(rec) + +/* The following two flags are usually "off" for i386, because some non-gnu + tools (for the i386) don't handle them. However, we don't have that + problem, so.... */ + +/* Forward references to tags are allowed. */ +#define SDB_ALLOW_FORWARD_REFERENCES + +/* Unknown tags are also allowed. */ +#define SDB_ALLOW_UNKNOWN_REFERENCES + +/* The integer half of this list needs to be constant. However, there's + a lot of disagreement about what the floating point adjustments should + be. We pick one that works with gdb. (The underlying problem is + what to do about the segment registers. Since we have access to them + from /proc, we'll allow them to be accessed in gdb, even tho the + gcc compiler can't generate them. (There's some evidence that + MSVC does, but possibly only for certain special "canned" sequences.) */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+8 \ + : (-1)) + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + Apply stddef, handle (as yet unimplemented) pic. + + stddef renaming does NOT apply to Alpha. */ + +char *gen_stdcall_suffix (); + +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + if (lookup_attribute ("stdcall", \ + TYPE_ATTRIBUTES (TREE_TYPE (DECL)))) \ + XEXP (DECL_RTL (DECL), 0) = \ + gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (DECL)); \ + } \ +while (0) + +/* This macro gets just the user-specified name + out of the string in a SYMBOL_REF. Discard + trailing @[NUM] encoded by ENCODE_SECTION_INFO. */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ +do { \ + char *_p; \ + char *_name = SYMBOL_NAME; \ + for (_p = _name; *_p && *_p != '@'; ++_p) \ + ; \ + if (*_p == '@') \ + { \ + int _len = _p - _name; \ + (VAR) = (char *) alloca (_len + 1); \ + strncpy ((VAR), _name, _len); \ + (VAR)[_len] = '\0'; \ + } \ + else \ + (VAR) = _name; \ +} while (0) + +#if 0 +/* Turn this back on when the linker is updated to handle grouped + .data$ sections correctly. See corresponding note in i386/interix.c. + MK. */ + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void i386_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) i386_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + static struct section_info \ + { \ + struct section_info *next; \ + char *name; \ + enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \ + } *sections; \ + struct section_info *s; \ + char *mode; \ + enum sect_enum type; \ + \ + for (s = sections; s; s = s->next) \ + if (!strcmp (NAME, s->name)) \ + break; \ + \ + if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \ + type = SECT_EXEC, mode = "x"; \ + else if (DECL && DECL_READONLY_SECTION (DECL, RELOC)) \ + type = SECT_RO, mode = "r"; \ + else \ + type = SECT_RW, mode = "w"; \ + \ + if (s == 0) \ + { \ + s = (struct section_info *) xmalloc (sizeof (struct section_info)); \ + s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \ + strcpy (s->name, NAME); \ + s->type = type; \ + s->next = sections; \ + sections = s; \ + fprintf (STREAM, ".section\t%s,\"%s\"\n", NAME, mode); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ + } \ + else \ + { \ + fprintf (STREAM, ".section\t%s,\"%s\"\n", NAME, mode); \ + } \ +} while (0) + +#endif /* 0 */ + +/* DWARF2 Unwinding doesn't work with exception handling yet. */ +#define DWARF2_UNWIND_INFO 0 + +/* Don't assume anything about the header files. */ +#define NO_IMPLICIT_EXTERN_C + diff --git a/gnu/egcs/gcc/config/i386/i386.c b/gnu/egcs/gcc/config/i386/i386.c new file mode 100644 index 00000000000..2e8236dcbbc --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386.c @@ -0,0 +1,5688 @@ +/* Subroutines for insn-output.c for Intel X86. + Copyright (C) 1988, 92, 94-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. */ + +#include <setjmp.h> +#include "config.h" +#include "system.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 "tree.h" +#include "flags.h" +#include "except.h" +#include "function.h" +#include "recog.h" +#include "expr.h" +#include "toplev.h" + +#ifdef EXTRA_CONSTRAINT +/* If EXTRA_CONSTRAINT is defined, then the 'S' + constraint in REG_CLASS_FROM_LETTER will no longer work, and various + asm statements that need 'S' for class SIREG will break. */ + error EXTRA_CONSTRAINT conflicts with S constraint letter +/* The previous line used to be #error, but some compilers barf + even if the conditional was untrue. */ +#endif + +#ifndef CHECK_STACK_LIMIT +#define CHECK_STACK_LIMIT -1 +#endif + +/* Type of an operand for ix86_{binary,unary}_operator_ok */ +enum reg_mem +{ + reg_p, + mem_p, + imm_p +}; + +/* Processor costs (relative to an add) */ +struct processor_costs i386_cost = { /* 386 specific costs */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 3, /* variable shift costs */ + 2, /* constant shift costs */ + 6, /* cost of starting a multiply */ + 1, /* cost of multiply per each bit set */ + 23 /* cost of a divide/mod */ +}; + +struct processor_costs i486_cost = { /* 486 specific costs */ + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 3, /* variable shift costs */ + 2, /* constant shift costs */ + 12, /* cost of starting a multiply */ + 1, /* cost of multiply per each bit set */ + 40 /* cost of a divide/mod */ +}; + +struct processor_costs pentium_cost = { + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 4, /* variable shift costs */ + 1, /* constant shift costs */ + 11, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 25 /* cost of a divide/mod */ +}; + +struct processor_costs pentiumpro_cost = { + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 3, /* variable shift costs */ + 1, /* constant shift costs */ + 4, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 17 /* cost of a divide/mod */ +}; + +/* We use decoding time together with execution time. + To get correct vale add 1 for short decodable, 2 for long decodable + and 4 for vector decodable instruction to execution time and divide + by two (because CPU is able to do two insns at a time). */ + +struct processor_costs k6_cost = { + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + 3, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 20 /* cost of a divide/mod */ +}; + +struct processor_costs *ix86_cost = &pentium_cost; + +/* Processor feature/optimization bitmasks. */ +#define m_386 (1<<PROCESSOR_I386) +#define m_486 (1<<PROCESSOR_I486) +#define m_PENT (1<<PROCESSOR_PENTIUM) +#define m_PPRO (1<<PROCESSOR_PENTIUMPRO) +#define m_K6 (1<<PROCESSOR_K6) + +const int x86_use_leave = m_386 | m_K6; +const int x86_push_memory = m_386 | m_K6; +const int x86_zero_extend_with_and = m_486 | m_PENT; +const int x86_movx = m_386 | m_PPRO | m_K6; +const int x86_double_with_add = ~(m_386 | m_PENT | m_PPRO); +const int x86_use_bit_test = m_386; +const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO; +const int x86_use_q_reg = m_PENT | m_PPRO | m_K6; +const int x86_use_any_reg = m_486; +const int x86_cmove = m_PPRO; +const int x86_deep_branch = m_PPRO| m_K6; + +#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx)) + +extern FILE *asm_out_file; +extern char *strcat (); + +static void ix86_epilogue PROTO((int)); +static void ix86_prologue PROTO((int)); + +char *singlemove_string (); +char *output_move_const_single (); +char *output_fp_cc0_set (); + +char *hi_reg_name[] = HI_REGISTER_NAMES; +char *qi_reg_name[] = QI_REGISTER_NAMES; +char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; + +/* Array of the smallest class containing reg number REGNO, indexed by + REGNO. Used by REGNO_REG_CLASS in i386.h. */ + +enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = +{ + /* ax, dx, cx, bx */ + AREG, DREG, CREG, BREG, + /* si, di, bp, sp */ + SIREG, DIREG, INDEX_REGS, GENERAL_REGS, + /* FP registers */ + FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS, + FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, + /* arg pointer */ + INDEX_REGS +}; + +/* Test and compare insns in i386.md store the information needed to + generate branch and scc insns here. */ + +struct rtx_def *i386_compare_op0 = NULL_RTX; +struct rtx_def *i386_compare_op1 = NULL_RTX; +struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); + +/* which cpu are we scheduling for */ +enum processor_type ix86_cpu; + +/* which instruction set architecture to use. */ +int ix86_arch; + +/* Strings to hold which cpu and instruction set architecture to use. */ +char *ix86_cpu_string; /* for -mcpu=<xxx> */ +char *ix86_arch_string; /* for -march=<xxx> */ + +/* Register allocation order */ +char *i386_reg_alloc_order; +static char regs_allocated[FIRST_PSEUDO_REGISTER]; + +/* # of registers to use to pass arguments. */ +char *i386_regparm_string; + +/* i386_regparm_string as a number */ +int i386_regparm; + +/* Alignment to use for loops and jumps: */ + +/* Power of two alignment for loops. */ +char *i386_align_loops_string; + +/* Power of two alignment for non-loop jumps. */ +char *i386_align_jumps_string; + +/* Power of two alignment for stack boundary in bytes. */ +char *i386_preferred_stack_boundary_string; + +/* Preferred alignment for stack boundary in bits. */ +int i386_preferred_stack_boundary; + +/* Values 1-5: see jump.c */ +int i386_branch_cost; +char *i386_branch_cost_string; + +/* Power of two alignment for functions. */ +int i386_align_funcs; +char *i386_align_funcs_string; + +/* Power of two alignment for loops. */ +int i386_align_loops; + +/* Power of two alignment for non-loop jumps. */ +int i386_align_jumps; + +/* 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 ch, i, j; + int def_align; + + static struct ptt + { + char *name; /* Canonical processor name. */ + enum processor_type processor; /* Processor type enum value. */ + struct processor_costs *cost; /* Processor costs */ + int target_enable; /* Target flags to enable. */ + int target_disable; /* Target flags to disable. */ + } processor_target_table[] = { + {PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0}, + {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0}, + {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0}, + {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0}, + {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost, 0, 0}, + {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO, + &pentiumpro_cost, 0, 0}, + {PROCESSOR_K6_STRING, PROCESSOR_K6, &k6_cost, 0, 0} + }; + + int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt); + +#ifdef SUBTARGET_OVERRIDE_OPTIONS + SUBTARGET_OVERRIDE_OPTIONS; +#endif + + /* Validate registers in register allocation order. */ + if (i386_reg_alloc_order) + { + for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + { + int regno = 0; + + switch (ch) + { + case 'a': regno = 0; break; + case 'd': regno = 1; break; + case 'c': regno = 2; break; + case 'b': regno = 3; break; + case 'S': regno = 4; break; + case 'D': regno = 5; break; + case 'B': regno = 6; break; + + default: fatal ("Register '%c' is unknown", ch); + } + + if (regs_allocated[regno]) + fatal ("Register '%c' already specified in allocation order", ch); + + regs_allocated[regno] = 1; + } + } + + if (ix86_arch_string == 0) + { + ix86_arch_string = PROCESSOR_PENTIUM_STRING; + if (ix86_cpu_string == 0) + ix86_cpu_string = PROCESSOR_DEFAULT_STRING; + } + + for (i = 0; i < ptt_size; i++) + if (! strcmp (ix86_arch_string, processor_target_table[i].name)) + { + ix86_arch = processor_target_table[i].processor; + if (ix86_cpu_string == 0) + ix86_cpu_string = processor_target_table[i].name; + break; + } + + if (i == ptt_size) + { + error ("bad value (%s) for -march= switch", ix86_arch_string); + ix86_arch_string = PROCESSOR_PENTIUM_STRING; + ix86_arch = PROCESSOR_DEFAULT; + } + + if (ix86_cpu_string == 0) + ix86_cpu_string = PROCESSOR_DEFAULT_STRING; + + for (j = 0; j < ptt_size; j++) + if (! strcmp (ix86_cpu_string, processor_target_table[j].name)) + { + ix86_cpu = processor_target_table[j].processor; + ix86_cost = processor_target_table[j].cost; + if (i > j && (int) ix86_arch >= (int) PROCESSOR_K6) + error ("-mcpu=%s does not support -march=%s", + ix86_cpu_string, ix86_arch_string); + + target_flags |= processor_target_table[j].target_enable; + target_flags &= ~processor_target_table[j].target_disable; + break; + } + + if (j == ptt_size) + { + error ("bad value (%s) for -mcpu= switch", ix86_cpu_string); + ix86_cpu_string = PROCESSOR_DEFAULT_STRING; + ix86_cpu = PROCESSOR_DEFAULT; + } + + /* Validate -mregparm= value. */ + if (i386_regparm_string) + { + i386_regparm = atoi (i386_regparm_string); + if (i386_regparm < 0 || i386_regparm > REGPARM_MAX) + fatal ("-mregparm=%d is not between 0 and %d", + i386_regparm, REGPARM_MAX); + } + + /* The 486 suffers more from non-aligned cache line fills, and the + larger code size results in a larger cache foot-print and more misses. + The 486 has a 16 byte cache line, pentium and pentiumpro have a 32 byte + cache line. */ + def_align = (TARGET_486) ? 4 : 2; + + /* Validate -malign-loops= value, or provide default. */ +#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN + i386_align_loops = 4; +#else + i386_align_loops = 2; +#endif + if (i386_align_loops_string) + { + i386_align_loops = atoi (i386_align_loops_string); + if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN) + fatal ("-malign-loops=%d is not between 0 and %d", + i386_align_loops, MAX_CODE_ALIGN); + } + + /* Validate -malign-jumps= value, or provide default. */ +#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN + i386_align_jumps = 4; +#else + i386_align_jumps = def_align; +#endif + if (i386_align_jumps_string) + { + i386_align_jumps = atoi (i386_align_jumps_string); + if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN) + fatal ("-malign-jumps=%d is not between 0 and %d", + i386_align_jumps, MAX_CODE_ALIGN); + } + + /* Validate -malign-functions= value, or provide default. */ + i386_align_funcs = def_align; + if (i386_align_funcs_string) + { + i386_align_funcs = atoi (i386_align_funcs_string); + if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN) + fatal ("-malign-functions=%d is not between 0 and %d", + i386_align_funcs, MAX_CODE_ALIGN); + } + + /* Validate -mpreferred_stack_boundary= value, or provide default. + The default of 128 bits is for Pentium III's SSE __m128. */ + i386_preferred_stack_boundary = 128; + if (i386_preferred_stack_boundary_string) + { + i = atoi (i386_preferred_stack_boundary_string); + if (i < 2 || i > 31) + fatal ("-mpreferred_stack_boundary=%d is not between 2 and 31", i); + i386_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; + } + + /* Validate -mbranch-cost= value, or provide default. */ + i386_branch_cost = 1; + if (i386_branch_cost_string) + { + i386_branch_cost = atoi (i386_branch_cost_string); + if (i386_branch_cost < 0 || i386_branch_cost > 5) + fatal ("-mbranch-cost=%d is not between 0 and 5", i386_branch_cost); + } + + /* Keep nonleaf frame pointers. */ + if (TARGET_OMIT_LEAF_FRAME_POINTER) + flag_omit_frame_pointer = 1; +} + +/* A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + +void +order_regs_for_local_alloc () +{ + int i, ch, order; + + /* User specified the register allocation order. */ + + if (i386_reg_alloc_order) + { + for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + { + int regno = 0; + + switch (ch) + { + case 'a': regno = 0; break; + case 'd': regno = 1; break; + case 'c': regno = 2; break; + case 'b': regno = 3; break; + case 'S': regno = 4; break; + case 'D': regno = 5; break; + case 'B': regno = 6; break; + } + + reg_alloc_order[order++] = regno; + } + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (! regs_allocated[i]) + reg_alloc_order[order++] = i; + } + } + + /* If user did not specify a register allocation order, use natural order. */ + else + { + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + reg_alloc_order[i] = i; + } +} + +void +optimization_options (level, size) + int level; + int size ATTRIBUTE_UNUSED; +{ + /* For -O2 and beyond, turn off -fschedule-insns by default. It tends to + make the problem with not enough registers even worse. */ +#ifdef INSN_SCHEDULING + if (level > 1) + flag_schedule_insns = 0; +#endif +} + +/* Sign-extend a 16-bit constant */ + +struct rtx_def * +i386_sext16_if_const (op) + struct rtx_def *op; +{ + if (GET_CODE (op) == CONST_INT) + { + HOST_WIDE_INT val = INTVAL (op); + HOST_WIDE_INT sext_val; + if (val & 0x8000) + sext_val = val | ~0xffff; + else + sext_val = val & 0xffff; + if (sext_val != val) + op = GEN_INT (sext_val); + } + return op; +} + +/* Return nonzero if the rtx is aligned */ + +static int +i386_aligned_reg_p (regno) + int regno; +{ + return (regno == STACK_POINTER_REGNUM + || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM)); +} + +int +i386_aligned_p (op) + rtx op; +{ + /* Registers and immediate operands are always "aligned". */ + if (GET_CODE (op) != MEM) + return 1; + + /* Don't even try to do any aligned optimizations with volatiles. */ + if (MEM_VOLATILE_P (op)) + return 0; + + /* Get address of memory operand. */ + op = XEXP (op, 0); + + switch (GET_CODE (op)) + { + case CONST_INT: + if (INTVAL (op) & 3) + break; + return 1; + + /* Match "reg + offset" */ + case PLUS: + if (GET_CODE (XEXP (op, 1)) != CONST_INT) + break; + if (INTVAL (XEXP (op, 1)) & 3) + break; + + op = XEXP (op, 0); + if (GET_CODE (op) != REG) + break; + + /* ... fall through ... */ + + case REG: + return i386_aligned_reg_p (REGNO (op)); + + default: + break; + } + + return 0; +} + +/* Return nonzero if INSN looks like it won't compute useful cc bits + as a side effect. This information is only a hint. */ + +int +i386_cc_probably_useless_p (insn) + rtx insn; +{ + return ! next_cc0_user (insn); +} + +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific + attribute for DECL. The attributes in ATTRIBUTES have previously been + assigned to DECL. */ + +int +i386_valid_decl_attribute_p (decl, attributes, identifier, args) + tree decl ATTRIBUTE_UNUSED; + tree attributes ATTRIBUTE_UNUSED; + tree identifier ATTRIBUTE_UNUSED; + tree args ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific + attribute for TYPE. The attributes in ATTRIBUTES have previously been + assigned to TYPE. */ + +int +i386_valid_type_attribute_p (type, attributes, identifier, args) + tree type; + tree attributes ATTRIBUTE_UNUSED; + tree identifier; + tree args; +{ + if (TREE_CODE (type) != FUNCTION_TYPE + && TREE_CODE (type) != METHOD_TYPE + && TREE_CODE (type) != FIELD_DECL + && TREE_CODE (type) != TYPE_DECL) + return 0; + + /* Stdcall attribute says callee is responsible for popping arguments + if they are not variable. */ + if (is_attribute_p ("stdcall", identifier)) + return (args == NULL_TREE); + + /* Cdecl attribute says the callee is a normal C declaration. */ + if (is_attribute_p ("cdecl", identifier)) + return (args == NULL_TREE); + + /* Regparm attribute specifies how many integer arguments are to be + passed in registers. */ + if (is_attribute_p ("regparm", identifier)) + { + tree cst; + + if (! args || TREE_CODE (args) != TREE_LIST + || TREE_CHAIN (args) != NULL_TREE + || TREE_VALUE (args) == NULL_TREE) + return 0; + + cst = TREE_VALUE (args); + if (TREE_CODE (cst) != INTEGER_CST) + return 0; + + if (TREE_INT_CST_HIGH (cst) != 0 + || TREE_INT_CST_LOW (cst) < 0 + || TREE_INT_CST_LOW (cst) > REGPARM_MAX) + return 0; + + return 1; + } + + return 0; +} + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ + +int +i386_comp_type_attributes (type1, type2) + tree type1; + tree type2; +{ + /* Check for mismatch of non-default calling convention. */ + char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; + + if (TREE_CODE (type1) != FUNCTION_TYPE) + return 1; + + /* Check for mismatched return types (cdecl vs stdcall). */ + if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) + != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) + return 0; + return 1; +} + + +/* Value is the number of bytes of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the 80386, 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. + + The attribute stdcall is equivalent to RTD on a per module basis. */ + +int +i386_return_pops_args (fundecl, funtype, size) + tree fundecl; + tree funtype; + int size; +{ + int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE); + + /* Cdecl functions override -mrtd, and never pop the stack. */ + if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) { + + /* Stdcall functions will pop the stack if not variable args. */ + if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) + rtd = 1; + + if (rtd + && (TYPE_ARG_TYPES (funtype) == NULL_TREE + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) + == void_type_node))) + return size; + } + + /* Lose any fake structure return argument. */ + if (aggregate_value_p (TREE_TYPE (funtype))) + return GET_MODE_SIZE (Pmode); + + return 0; +} + + +/* Argument support functions. */ + +/* 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. */ + +void +init_cumulative_args (cum, fntype, libname) + CUMULATIVE_ARGS *cum; /* Argument info to initialize */ + tree fntype; /* tree ptr for function decl */ + rtx libname; /* SYMBOL_REF of library name or 0 */ +{ + static CUMULATIVE_ARGS zero_cum; + tree param, next_param; + + if (TARGET_DEBUG_ARG) + { + fprintf (stderr, "\ninit_cumulative_args ("); + if (fntype) + fprintf (stderr, "fntype code = %s, ret code = %s", + tree_code_name[(int) TREE_CODE (fntype)], + tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]); + else + fprintf (stderr, "no fntype"); + + if (libname) + fprintf (stderr, ", libname = %s", XSTR (libname, 0)); + } + + *cum = zero_cum; + + /* Set up the number of registers to use for passing arguments. */ + cum->nregs = i386_regparm; + if (fntype) + { + tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); + + if (attr) + cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); + } + + /* Determine if this function has variable arguments. This is + indicated by the last argument being 'void_type_mode' if there + are no variable arguments. If there are variable arguments, then + we won't pass anything in registers */ + + if (cum->nregs) + { + for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; + param != 0; param = next_param) + { + next_param = TREE_CHAIN (param); + if (next_param == 0 && TREE_VALUE (param) != void_type_node) + cum->nregs = 0; + } + } + + if (TARGET_DEBUG_ARG) + fprintf (stderr, ", nregs=%d )\n", cum->nregs); + + return; +} + +/* 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.) */ + +void +function_arg_advance (cum, mode, type, named) + CUMULATIVE_ARGS *cum; /* current arg information */ + enum machine_mode mode; /* current arg mode */ + tree type; /* type of the argument or 0 if lib support */ + int named; /* whether or not the argument was named */ +{ + int bytes + = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + if (TARGET_DEBUG_ARG) + fprintf (stderr, + "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n", + words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); + + cum->words += words; + cum->nregs -= words; + cum->regno += words; + + if (cum->nregs <= 0) + { + cum->nregs = 0; + cum->regno = 0; + } + + return; +} + +/* 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). */ + +struct rtx_def * +function_arg (cum, mode, type, named) + CUMULATIVE_ARGS *cum; /* current arg information */ + enum machine_mode mode; /* current arg mode */ + tree type; /* type of the argument or 0 if lib support */ + int named; /* != 0 for normal args, == 0 for ... args */ +{ + rtx ret = NULL_RTX; + int bytes + = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + switch (mode) + { + /* For now, pass fp/complex values on the stack. */ + default: + break; + + case BLKmode: + case DImode: + case SImode: + case HImode: + case QImode: + if (words <= cum->nregs) + ret = gen_rtx_REG (mode, cum->regno); + break; + } + + if (TARGET_DEBUG_ARG) + { + fprintf (stderr, + "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d", + words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); + + if (ret) + fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]); + else + fprintf (stderr, ", stack"); + + fprintf (stderr, " )\n"); + } + + return ret; +} + +/* 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. */ + +int +function_arg_partial_nregs (cum, mode, type, named) + CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; /* current arg information */ + enum machine_mode mode ATTRIBUTE_UNUSED; /* current arg mode */ + tree type ATTRIBUTE_UNUSED; /* type of the argument or 0 if lib support */ + int named ATTRIBUTE_UNUSED; /* != 0 for normal args, == 0 for ... args */ +{ + return 0; +} + +char * +singlemove_string (operands) + rtx *operands; +{ + rtx x; + if (GET_CODE (operands[0]) == MEM + && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC) + { + if (XEXP (x, 0) != stack_pointer_rtx) + abort (); + return "push%L1 %1"; + } + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG) + return AS2 (mov%L0,%1,%0); + else if (CONSTANT_P (operands[1])) + return AS2 (mov%L0,%1,%0); + else + { + output_asm_insn ("push%L1 %1", operands); + return "pop%L0 %0"; + } +} + +/* Output an insn to add the constant N to the register X. */ + +static void +asm_add (n, x) + int n; + rtx x; +{ + rtx xops[2]; + xops[0] = x; + + if (n == -1) + output_asm_insn (AS1 (dec%L0,%0), xops); + else if (n == 1) + output_asm_insn (AS1 (inc%L0,%0), xops); + else if (n < 0 || n == 128) + { + xops[1] = GEN_INT (-n); + output_asm_insn (AS2 (sub%L0,%1,%0), xops); + } + else if (n > 0) + { + xops[1] = GEN_INT (n); + output_asm_insn (AS2 (add%L0,%1,%0), xops); + } +} + +/* 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]; + 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 are not supposed to happen + either due to the operand constraints or the fact + that all memory operands on the x86 are offsettable. + Abort if we get one, because generating code for these + cases is painful. */ + + if (optype0 == RNDOP || optype1 == RNDOP + || optype0 == MEMOP || optype1 == MEMOP) + 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) + { + /* ??? Can this ever happen on i386? */ + operands[0] = XEXP (XEXP (operands[0], 0), 0); + asm_add (-size, operands[0]); + 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) + { + /* ??? Can this ever happen on i386? */ + operands[1] = XEXP (XEXP (operands[1], 0), 0); + asm_add (-size, operands[1]); + 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; + } + + /* 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) + { + middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); + } + else if (optype0 == OFFSOP) + { + middlehalf[0] = adj_offsettable_operand (operands[0], 4); + latehalf[0] = adj_offsettable_operand (operands[0], 8); + } + else + { + middlehalf[0] = operands[0]; + latehalf[0] = operands[0]; + } + + if (optype1 == REGOP) + { + middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); + } + else if (optype1 == OFFSOP) + { + middlehalf[1] = adj_offsettable_operand (operands[1], 4); + latehalf[1] = adj_offsettable_operand (operands[1], 8); + } + 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])) + /* No non-CONST_DOUBLE constant should ever appear here. */ + abort (); + } + 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], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) + split_double (operands[1], &operands[1], &latehalf[1]); + else + latehalf[1] = operands[1]; + } + + /* If insn is effectively movd N (sp),-(sp) then we will do the + high word first. We should use the adjusted operand 1 + (which is N+4 (sp) or N+8 (sp)) + for the low word and middle 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])) + middlehalf[1] = operands[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) + { + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + compute the address into latehalf of dest. */ + compadr: + xops[0] = latehalf[0]; + xops[1] = XEXP (operands[1], 0); + output_asm_insn (AS2 (lea%L0,%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_mentioned_p (middlehalf[0], XEXP (operands[1], 0))) + { + /* Check for two regs used by both source and dest. */ + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + goto compadr; + + /* 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_mentioned_p (operands[0], 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 0 + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) + || dest_overlapped_low) +#endif + + 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) + { + /* Do the high-numbered word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + if (size == 12) + output_asm_insn (singlemove_string (middlehalf), middlehalf); + + /* 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) + output_asm_insn (singlemove_string (middlehalf), middlehalf); + + /* Do the high-numbered word. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + + return ""; +} + +#define MAX_TMPS 2 /* max temporary registers used */ + +/* Output the appropriate code to move push memory on the stack */ + +char * +output_move_pushmem (operands, insn, length, tmp_start, n_operands) + rtx operands[]; + rtx insn; + int length; + int tmp_start; + int n_operands; +{ + struct + { + char *load; + char *push; + rtx xops[2]; + } tmp_info[MAX_TMPS]; + + rtx src = operands[1]; + int max_tmps = 0; + int offset = 0; + int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src); + int stack_offset = 0; + int i, num_tmps; + rtx xops[1]; + + if (! offsettable_memref_p (src)) + fatal_insn ("Source is not offsettable", insn); + + if ((length & 3) != 0) + fatal_insn ("Pushing non-word aligned size", insn); + + /* Figure out which temporary registers we have available */ + for (i = tmp_start; i < n_operands; i++) + { + if (GET_CODE (operands[i]) == REG) + { + if (reg_overlap_mentioned_p (operands[i], src)) + continue; + + tmp_info[ max_tmps++ ].xops[1] = operands[i]; + if (max_tmps == MAX_TMPS) + break; + } + } + + if (max_tmps == 0) + for (offset = length - 4; offset >= 0; offset -= 4) + { + xops[0] = adj_offsettable_operand (src, offset + stack_offset); + output_asm_insn (AS1(push%L0,%0), xops); + if (stack_p) + stack_offset += 4; + } + + else + for (offset = length - 4; offset >= 0; ) + { + for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++) + { + tmp_info[num_tmps].load = AS2(mov%L0,%0,%1); + tmp_info[num_tmps].push = AS1(push%L0,%1); + tmp_info[num_tmps].xops[0] + = adj_offsettable_operand (src, offset + stack_offset); + offset -= 4; + } + + for (i = 0; i < num_tmps; i++) + output_asm_insn (tmp_info[i].load, tmp_info[i].xops); + + for (i = 0; i < num_tmps; i++) + output_asm_insn (tmp_info[i].push, tmp_info[i].xops); + + if (stack_p) + stack_offset += 4*num_tmps; + } + + return ""; +} + +int +standard_80387_constant_p (x) + rtx x; +{ +#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) + REAL_VALUE_TYPE d; + jmp_buf handler; + int is0, is1; + + if (setjmp (handler)) + return 0; + + set_float_handler (handler); + REAL_VALUE_FROM_CONST_DOUBLE (d, x); + is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d); + is1 = REAL_VALUES_EQUAL (d, dconst1); + set_float_handler (NULL_PTR); + + if (is0) + return 1; + + if (is1) + return 2; + + /* Note that on the 80387, other constants, such as pi, + are much slower to load as standard constants + than to load from doubles in memory! */ + /* ??? Not true on K6: all constants are equal cost. */ +#endif + + return 0; +} + +char * +output_move_const_single (operands) + rtx *operands; +{ + if (FP_REG_P (operands[0])) + { + int conval = standard_80387_constant_p (operands[1]); + + if (conval == 1) + return "fldz"; + + if (conval == 2) + return "fld1"; + } + + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + REAL_VALUE_TYPE r; long l; + + if (GET_MODE (operands[1]) == XFmode) + abort (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (r, l); + operands[1] = GEN_INT (l); + } + + return singlemove_string (operands); +} + +/* 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); + + default: + return 0; + } +} + +/* Return nonzero if OP is a constant shift count small enough to + encode into an lea instruction. */ + +int +small_shift_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4); +} + +/* Test for a valid operand for a call instruction. + Don't allow the arg pointer register or virtual regs + since they may change into reg + const, which the patterns + can't handle yet. */ + +int +call_insn_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == MEM + && ((CONSTANT_ADDRESS_P (XEXP (op, 0)) + /* This makes a difference for PIC. */ + && general_operand (XEXP (op, 0), Pmode)) + || (GET_CODE (XEXP (op, 0)) == REG + && XEXP (op, 0) != arg_pointer_rtx + && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER + && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) + return 1; + + return 0; +} + +/* Like call_insn_operand but allow (mem (symbol_ref ...)) + even if pic. */ + +int +expander_call_insn_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == MEM + && (CONSTANT_ADDRESS_P (XEXP (op, 0)) + || (GET_CODE (XEXP (op, 0)) == REG + && XEXP (op, 0) != arg_pointer_rtx + && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER + && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) + return 1; + + return 0; +} + +/* Return 1 if OP is a comparison operator that can use the condition code + generated by an arithmetic operation. */ + +int +arithmetic_comparison_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + enum rtx_code code; + + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + code = GET_CODE (op); + if (GET_RTX_CLASS (code) != '<') + return 0; + + return (code != GT && code != LE); +} + +int +ix86_logical_operator (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR; +} + + +/* Returns 1 if OP contains a symbol reference */ + +int +symbolic_reference_mentioned_p (op) + rtx op; +{ + register char *fmt; + register int i; + + if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (op, i) - 1; j >= 0; j--) + if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) + return 1; + } + + else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) + return 1; + } + + return 0; +} + +/* Attempt to expand a binary operator. Make the expansion closer to the + actual machine, then just general_operand, which will allow 3 separate + memory references (one output, two input) in a single insn. Return + whether the insn fails, or succeeds. */ + +int +ix86_expand_binary_operator (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx operands[]; +{ + int modified; + + /* Recognize <var1> = <value> <op> <var1> for commutative operators */ + if (GET_RTX_CLASS (code) == 'c' + && (rtx_equal_p (operands[0], operands[2]) + || immediate_operand (operands[1], mode))) + { + rtx temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } + + /* If optimizing, copy to regs to improve CSE */ + if (TARGET_PSEUDO && optimize + && ((reload_in_progress | reload_completed) == 0)) + { + if (GET_CODE (operands[1]) == MEM + && ! rtx_equal_p (operands[0], operands[1])) + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + + if (GET_CODE (operands[2]) == MEM) + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + + if (GET_CODE (operands[1]) == CONST_INT && code == MINUS) + { + rtx temp = gen_reg_rtx (GET_MODE (operands[0])); + + emit_move_insn (temp, operands[1]); + operands[1] = temp; + return TRUE; + } + } + + if (!ix86_binary_operator_ok (code, mode, operands)) + { + /* If not optimizing, try to make a valid insn (optimize code + previously did this above to improve chances of CSE) */ + + if ((! TARGET_PSEUDO || !optimize) + && ((reload_in_progress | reload_completed) == 0) + && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)) + { + modified = FALSE; + if (GET_CODE (operands[1]) == MEM + && ! rtx_equal_p (operands[0], operands[1])) + { + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + modified = TRUE; + } + + if (GET_CODE (operands[2]) == MEM) + { + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + modified = TRUE; + } + + if (GET_CODE (operands[1]) == CONST_INT && code == MINUS) + { + rtx temp = gen_reg_rtx (GET_MODE (operands[0])); + + emit_move_insn (temp, operands[1]); + operands[1] = temp; + return TRUE; + } + + if (modified && ! ix86_binary_operator_ok (code, mode, operands)) + return FALSE; + } + else + return FALSE; + } + + return TRUE; +} + +/* Return TRUE or FALSE depending on whether the binary operator meets the + appropriate constraints. */ + +int +ix86_binary_operator_ok (code, mode, operands) + enum rtx_code code; + enum machine_mode mode ATTRIBUTE_UNUSED; + rtx operands[3]; +{ + return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM) + && (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c'); +} + +/* Attempt to expand a unary operator. Make the expansion closer to the + actual machine, then just general_operand, which will allow 2 separate + memory references (one output, one input) in a single insn. Return + whether the insn fails, or succeeds. */ + +int +ix86_expand_unary_operator (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx operands[]; +{ + /* If optimizing, copy to regs to improve CSE */ + if (TARGET_PSEUDO + && optimize + && ((reload_in_progress | reload_completed) == 0) + && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + + if (! ix86_unary_operator_ok (code, mode, operands)) + { + if ((! TARGET_PSEUDO || optimize == 0) + && ((reload_in_progress | reload_completed) == 0) + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + if (! ix86_unary_operator_ok (code, mode, operands)) + return FALSE; + } + else + return FALSE; + } + + return TRUE; +} + +/* Return TRUE or FALSE depending on whether the unary operator meets the + appropriate constraints. */ + +int +ix86_unary_operator_ok (code, mode, operands) + enum rtx_code code ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; + rtx operands[2] ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +static rtx pic_label_rtx; +static char pic_label_name [256]; +static int pic_label_no = 0; + +/* This function generates code for -fpic that loads %ebx with + the return address of the caller and then returns. */ + +void +asm_output_function_prefix (file, name) + FILE *file; + char *name ATTRIBUTE_UNUSED; +{ + rtx xops[2]; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + xops[0] = pic_offset_table_rtx; + xops[1] = stack_pointer_rtx; + + /* Deep branch prediction favors having a return for every call. */ + if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION) + { + tree prologue_node; + + if (pic_label_rtx == 0) + { + pic_label_rtx = gen_label_rtx (); + ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++); + LABEL_NAME (pic_label_rtx) = pic_label_name; + } + + prologue_node = make_node (FUNCTION_DECL); + DECL_RESULT (prologue_node) = 0; + + /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an + internal (non-global) label that's being emitted, it didn't make + sense to have .type information for local labels. This caused + the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving + me debug info for a label that you're declaring non-global?) this + was changed to call ASM_OUTPUT_LABEL() instead. */ + + + ASM_OUTPUT_LABEL (file, pic_label_name); + output_asm_insn ("movl (%1),%0", xops); + output_asm_insn ("ret", xops); + } +} + +/* Generate the assembly code for function entry. + FILE is an stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to allocate. */ + +void +function_prologue (file, size) + FILE *file ATTRIBUTE_UNUSED; + int size ATTRIBUTE_UNUSED; +{ + if (TARGET_SCHEDULE_PROLOGUE) + { + pic_label_rtx = 0; + return; + } + + ix86_prologue (0); +} + +/* Expand the prologue into a bunch of separate insns. */ + +void +ix86_expand_prologue () +{ + if (! TARGET_SCHEDULE_PROLOGUE) + return; + + ix86_prologue (1); +} + +void +load_pic_register (do_rtl) + int do_rtl; +{ + rtx xops[4]; + + if (TARGET_DEEP_BRANCH_PREDICTION) + { + xops[0] = pic_offset_table_rtx; + if (pic_label_rtx == 0) + { + pic_label_rtx = gen_label_rtx (); + ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++); + LABEL_NAME (pic_label_rtx) = pic_label_name; + } + + xops[1] = gen_rtx_MEM (QImode, + gen_rtx (SYMBOL_REF, Pmode, + LABEL_NAME (pic_label_rtx))); + + if (do_rtl) + { + emit_insn (gen_prologue_get_pc (xops[0], xops[1])); + emit_insn (gen_prologue_set_got (xops[0], +#ifdef YES_UNDERSCORES + gen_rtx_SYMBOL_REF (Pmode, + "$__GLOBAL_OFFSET_TABLE_"), +#else + gen_rtx_SYMBOL_REF (Pmode, + "$_GLOBAL_OFFSET_TABLE_"), +#endif + xops[1])); + } + else + { + output_asm_insn (AS1 (call,%X1), xops); + output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_,%0", xops); + pic_label_rtx = 0; + } + } + + else + { + xops[0] = pic_offset_table_rtx; + xops[1] = gen_label_rtx (); + + if (do_rtl) + { + /* We can't put a raw CODE_LABEL into the RTL, and we can't emit + a new CODE_LABEL after reload, so we need a single pattern to + emit the 3 necessary instructions. */ + emit_insn (gen_prologue_get_pc_and_set_got (xops[0])); + } + else + { + output_asm_insn (AS1 (call,%P1), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[1])); + output_asm_insn (AS1 (pop%L0,%0), xops); + output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); + } + } + + /* When -fpic, we must emit a scheduling barrier, so that the instruction + that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get + moved before any instruction which implicitly uses the got. */ + + if (do_rtl) + emit_insn (gen_blockage ()); +} + +/* Compute the size of local storage taking into consideration the + desired stack alignment which is to be maintained. Also determine + the number of registers saved below the local storage. */ + +HOST_WIDE_INT +ix86_compute_frame_size (size, nregs_on_stack) + HOST_WIDE_INT size; + int *nregs_on_stack; +{ + int limit; + int nregs; + int regno; + int padding; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + HOST_WIDE_INT total_size; + + limit = frame_pointer_needed + ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; + + nregs = 0; + + for (regno = limit - 1; regno >= 0; regno--) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + nregs++; + + padding = 0; + total_size = size + (nregs * UNITS_PER_WORD); + +#ifdef PREFERRED_STACK_BOUNDARY + { + int offset; + int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; + + offset = 4; + if (frame_pointer_needed) + offset += UNITS_PER_WORD; + + total_size += offset; + + padding = ((total_size + preferred_alignment - 1) + & -preferred_alignment) - total_size; + + if (padding < (((offset + preferred_alignment - 1) + & -preferred_alignment) - offset)) + padding += preferred_alignment; + + /* Don't bother aligning the stack of a leaf function + which doesn't allocate any stack slots. */ + if (size == 0 && current_function_is_leaf) + padding = 0; + } +#endif + + if (nregs_on_stack) + *nregs_on_stack = nregs; + + return size + padding; +} + +static void +ix86_prologue (do_rtl) + int do_rtl; +{ + register int regno; + int limit; + rtx xops[4]; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0); + rtx insn; + int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset; + + xops[0] = stack_pointer_rtx; + xops[1] = frame_pointer_rtx; + xops[2] = GEN_INT (tsize); + + if (frame_pointer_needed) + { + if (do_rtl) + { + insn = emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx_MEM (SImode, + gen_rtx (PRE_DEC, SImode, + stack_pointer_rtx)), + frame_pointer_rtx)); + + RTX_FRAME_RELATED_P (insn) = 1; + insn = emit_move_insn (xops[1], xops[0]); + RTX_FRAME_RELATED_P (insn) = 1; + } + + else + { + output_asm_insn ("push%L1 %1", xops); +#ifdef INCOMING_RETURN_ADDR_RTX + if (dwarf2out_do_frame ()) + { + char *l = dwarf2out_cfi_label (); + + cfa_store_offset += 4; + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); + dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset); + } +#endif + + output_asm_insn (AS2 (mov%L0,%0,%1), xops); +#ifdef INCOMING_RETURN_ADDR_RTX + if (dwarf2out_do_frame ()) + dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset); +#endif + } + } + + if (tsize == 0) + ; + else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT) + { + if (do_rtl) + { + insn = emit_insn (gen_prologue_set_stack_ptr (xops[2])); + RTX_FRAME_RELATED_P (insn) = 1; + } + else + { + output_asm_insn (AS2 (sub%L0,%2,%0), xops); +#ifdef INCOMING_RETURN_ADDR_RTX + if (dwarf2out_do_frame ()) + { + cfa_store_offset += tsize; + if (! frame_pointer_needed) + { + cfa_offset = cfa_store_offset; + dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); + } + } +#endif + } + } + else + { + xops[3] = gen_rtx_REG (SImode, 0); + if (do_rtl) + emit_move_insn (xops[3], xops[2]); + else + output_asm_insn (AS2 (mov%L0,%2,%3), xops); + + xops[3] = gen_rtx_MEM (FUNCTION_MODE, + gen_rtx (SYMBOL_REF, Pmode, "_alloca")); + + if (do_rtl) + emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx)); + else + output_asm_insn (AS1 (call,%P3), xops); + } + + /* Note If use enter it is NOT reversed args. + This one is not reversed from intel!! + I think enter is slower. Also sdb doesn't like it. + But if you want it the code is: + { + xops[3] = const0_rtx; + output_asm_insn ("enter %2,%3", xops); + } + */ + + limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + for (regno = limit - 1; regno >= 0; regno--) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + xops[0] = gen_rtx_REG (SImode, regno); + if (do_rtl) + { + insn = emit_insn (gen_rtx (SET, VOIDmode, + gen_rtx_MEM (SImode, + gen_rtx (PRE_DEC, SImode, + stack_pointer_rtx)), + xops[0])); + + RTX_FRAME_RELATED_P (insn) = 1; + } + else + { + output_asm_insn ("push%L0 %0", xops); +#ifdef INCOMING_RETURN_ADDR_RTX + if (dwarf2out_do_frame ()) + { + char *l = 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, regno, - cfa_store_offset); + } +#endif + } + } + +#ifdef SUBTARGET_PROLOGUE + SUBTARGET_PROLOGUE; +#endif + + if (pic_reg_used) + load_pic_register (do_rtl); + + /* If we are profiling, make sure no instructions are scheduled before + the call to mcount. However, if -fpic, the above call will have + done that. */ + if ((profile_flag || profile_block_flag) + && ! pic_reg_used && do_rtl) + emit_insn (gen_blockage ()); +} + +/* Return 1 if it is appropriate to emit `ret' instructions in the + body of a function. Do this only if the epilogue is simple, needing a + couple of insns. Prior to reloading, we can't tell how many registers + must be saved, so return 0 then. Return 0 if there is no frame + marker to de-allocate. + + If NON_SAVING_SETJMP is defined and true, then it is not possible + for the epilogue to be simple, so return 0. This is a special case + since NON_SAVING_SETJMP will not cause regs_ever_live to change + until final, but jump_optimize may need to know sooner if a + `return' is OK. */ + +int +ix86_can_use_return_insn_p () +{ + int regno; + int nregs = 0; + int reglimit = (frame_pointer_needed + ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + +#ifdef NON_SAVING_SETJMP + if (NON_SAVING_SETJMP && current_function_calls_setjmp) + return 0; +#endif + + if (! reload_completed) + return 0; + + for (regno = reglimit - 1; regno >= 0; regno--) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + nregs++; + + return nregs == 0 || ! frame_pointer_needed; +} + +/* This function generates the assembly code for function exit. + FILE is an stdio stream to output the code to. + SIZE is an int: how many units of temporary storage to deallocate. */ + +void +function_epilogue (file, size) + FILE *file ATTRIBUTE_UNUSED; + int size ATTRIBUTE_UNUSED; +{ + return; +} + +/* Restore function stack, frame, and registers. */ + +void +ix86_expand_epilogue () +{ + ix86_epilogue (1); +} + +static void +ix86_epilogue (do_rtl) + int do_rtl; +{ + register int regno; + register int limit; + int nregs; + rtx xops[3]; + int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool); + int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; + HOST_WIDE_INT offset; + HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs); + + /* sp is often unreliable so we may have to go off the frame pointer. */ + + offset = -(tsize + nregs * UNITS_PER_WORD); + + xops[2] = stack_pointer_rtx; + + /* When -fpic, we must emit a scheduling barrier, so that the instruction + that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get + moved before any instruction which implicitly uses the got. This + includes any instruction which uses a SYMBOL_REF or a LABEL_REF. + + Alternatively, this could be fixed by making the dependence on the + PIC_OFFSET_TABLE_REGNUM explicit in the RTL. */ + + if (flag_pic || profile_flag || profile_block_flag) + emit_insn (gen_blockage ()); + + /* If we're only restoring one register and sp is not valid then + using a move instruction to restore the register since it's + less work than reloading sp and popping the register. Otherwise, + restore sp (if necessary) and pop the registers. */ + + limit = frame_pointer_needed + ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; + + if (nregs > 1 || sp_valid) + { + if ( !sp_valid ) + { + xops[0] = adj_offsettable_operand (AT_BP (QImode), offset); + if (do_rtl) + emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0))); + else + output_asm_insn (AS2 (lea%L2,%0,%2), xops); + } + + for (regno = 0; regno < limit; regno++) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + xops[0] = gen_rtx_REG (SImode, regno); + + if (do_rtl) + emit_insn (gen_pop (xops[0])); + else + output_asm_insn ("pop%L0 %0", xops); + } + } + + else + for (regno = 0; regno < limit; regno++) + if ((regs_ever_live[regno] && ! call_used_regs[regno]) + || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + { + xops[0] = gen_rtx_REG (SImode, regno); + xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset); + + if (do_rtl) + emit_move_insn (xops[0], xops[1]); + else + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + offset += 4; + } + + if (frame_pointer_needed) + { + /* If not an i386, mov & pop is faster than "leave". */ + + if (TARGET_USE_LEAVE) + { + if (do_rtl) + emit_insn (gen_leave()); + else + output_asm_insn ("leave", xops); + } + else + { + xops[0] = frame_pointer_rtx; + xops[1] = stack_pointer_rtx; + + if (do_rtl) + { + emit_insn (gen_epilogue_set_stack_ptr()); + emit_insn (gen_pop (xops[0])); + } + else + { + output_asm_insn (AS2 (mov%L2,%0,%2), xops); + output_asm_insn ("pop%L0 %0", xops); + } + } + } + + else if (tsize) + { + /* Intel's docs say that for 4 or 8 bytes of stack frame one should + use `pop' and not `add'. */ + int use_pop = tsize == 4; + + /* Use two pops only for the Pentium processors. */ + if (tsize == 8 && !TARGET_386 && !TARGET_486) + { + rtx retval = current_function_return_rtx; + + xops[1] = gen_rtx_REG (SImode, 1); /* %edx */ + + /* This case is a bit more complex. Since we cannot pop into + %ecx twice we need a second register. But this is only + available if the return value is not of DImode in which + case the %edx register is not available. */ + use_pop = (retval == NULL + || ! reg_overlap_mentioned_p (xops[1], retval)); + } + + if (use_pop) + { + xops[0] = gen_rtx_REG (SImode, 2); /* %ecx */ + + if (do_rtl) + { + /* We have to prevent the two pops here from being scheduled. + GCC otherwise would try in some situation to put other + instructions in between them which has a bad effect. */ + emit_insn (gen_blockage ()); + emit_insn (gen_pop (xops[0])); + if (tsize == 8) + emit_insn (gen_pop (xops[1])); + } + else + { + output_asm_insn ("pop%L0 %0", xops); + if (tsize == 8) + output_asm_insn ("pop%L1 %1", xops); + } + } + else + { + /* If there is no frame pointer, we must still release the frame. */ + xops[0] = GEN_INT (tsize); + + if (do_rtl) + emit_insn (gen_rtx (SET, VOIDmode, xops[2], + gen_rtx (PLUS, SImode, xops[2], xops[0]))); + else + output_asm_insn (AS2 (add%L2,%0,%2), xops); + } + } + +#ifdef FUNCTION_BLOCK_PROFILER_EXIT + if (profile_block_flag == 2) + { + FUNCTION_BLOCK_PROFILER_EXIT(file); + } +#endif + + if (current_function_pops_args && current_function_args_size) + { + xops[1] = GEN_INT (current_function_pops_args); + + /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If + asked to pop more, pop return address, do explicit add, and jump + indirectly to the caller. */ + + if (current_function_pops_args >= 32768) + { + /* ??? Which register to use here? */ + xops[0] = gen_rtx_REG (SImode, 2); + + if (do_rtl) + { + emit_insn (gen_pop (xops[0])); + emit_insn (gen_rtx (SET, VOIDmode, xops[2], + gen_rtx (PLUS, SImode, xops[1], xops[2]))); + emit_jump_insn (xops[0]); + } + else + { + output_asm_insn ("pop%L0 %0", xops); + output_asm_insn (AS2 (add%L2,%1,%2), xops); + output_asm_insn ("jmp %*%0", xops); + } + } + else + { + if (do_rtl) + emit_jump_insn (gen_return_pop_internal (xops[1])); + else + output_asm_insn ("ret %1", xops); + } + } + else + { + if (do_rtl) + emit_jump_insn (gen_return_internal ()); + else + output_asm_insn ("ret", xops); + } +} + +/* 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. + + On x86, legitimate addresses are: + base movl (base),reg + displacement movl disp,reg + base + displacement movl disp(base),reg + index + base movl (base,index),reg + (index + base) + displacement movl disp(base,index),reg + index*scale movl (,index,scale),reg + index*scale + disp movl disp(,index,scale),reg + index*scale + base movl (base,index,scale),reg + (index*scale + base) + disp movl disp(base,index,scale),reg + + In each case, scale can be 1, 2, 4, 8. */ + +/* This is exactly the same as print_operand_addr, except that + it recognizes addresses instead of printing them. + + It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should + convert common non-canonical forms to canonical form so that they will + be recognized. */ + +#define ADDR_INVALID(msg,insn) \ +do { \ + if (TARGET_DEBUG_ADDR) \ + { \ + fprintf (stderr, msg); \ + debug_rtx (insn); \ + } \ +} while (0) + +int +legitimate_pic_address_disp_p (disp) + register rtx disp; +{ + if (GET_CODE (disp) != CONST) + return 0; + disp = XEXP (disp, 0); + + if (GET_CODE (disp) == PLUS) + { + if (GET_CODE (XEXP (disp, 1)) != CONST_INT) + return 0; + disp = XEXP (disp, 0); + } + + if (GET_CODE (disp) != UNSPEC + || XVECLEN (disp, 0) != 1) + return 0; + + /* Must be @GOT or @GOTOFF. */ + if (XINT (disp, 1) != 6 + && XINT (disp, 1) != 7) + return 0; + + if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF + && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF) + return 0; + + return 1; +} + +int +legitimate_address_p (mode, addr, strict) + enum machine_mode mode; + register rtx addr; + int strict; +{ + rtx base = NULL_RTX; + rtx indx = NULL_RTX; + rtx scale = NULL_RTX; + rtx disp = NULL_RTX; + + if (TARGET_DEBUG_ADDR) + { + fprintf (stderr, + "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n", + GET_MODE_NAME (mode), strict); + + debug_rtx (addr); + } + + if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG) + base = addr; + + else if (GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + enum rtx_code code0 = GET_CODE (op0); + enum rtx_code code1 = GET_CODE (op1); + + if (code0 == REG || code0 == SUBREG) + { + if (code1 == REG || code1 == SUBREG) + { + indx = op0; /* index + base */ + base = op1; + } + + else + { + base = op0; /* base + displacement */ + disp = op1; + } + } + + else if (code0 == MULT) + { + indx = XEXP (op0, 0); + scale = XEXP (op0, 1); + + if (code1 == REG || code1 == SUBREG) + base = op1; /* index*scale + base */ + + else + disp = op1; /* index*scale + disp */ + } + + else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) + { + indx = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */ + scale = XEXP (XEXP (op0, 0), 1); + base = XEXP (op0, 1); + disp = op1; + } + + else if (code0 == PLUS) + { + indx = XEXP (op0, 0); /* index + base + disp */ + base = XEXP (op0, 1); + disp = op1; + } + + else + { + ADDR_INVALID ("PLUS subcode is not valid.\n", op0); + return FALSE; + } + } + + else if (GET_CODE (addr) == MULT) + { + indx = XEXP (addr, 0); /* index*scale */ + scale = XEXP (addr, 1); + } + + else + disp = addr; /* displacement */ + + /* Allow arg pointer and stack pointer as index if there is not scaling */ + if (base && indx && !scale + && (indx == arg_pointer_rtx || indx == stack_pointer_rtx)) + { + rtx tmp = base; + base = indx; + indx = tmp; + } + + /* Validate base register: + + Don't allow SUBREG's here, it can lead to spill failures when the base + is one word out of a two word structure, which is represented internally + as a DImode int. */ + + if (base) + { + if (GET_CODE (base) != REG) + { + ADDR_INVALID ("Base is not a register.\n", base); + return FALSE; + } + + if (GET_MODE (base) != Pmode) + { + ADDR_INVALID ("Base is not in Pmode.\n", base); + return FALSE; + } + + if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base)) + || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base))) + { + ADDR_INVALID ("Base is not valid.\n", base); + return FALSE; + } + } + + /* Validate index register: + + Don't allow SUBREG's here, it can lead to spill failures when the index + is one word out of a two word structure, which is represented internally + as a DImode int. */ + if (indx) + { + if (GET_CODE (indx) != REG) + { + ADDR_INVALID ("Index is not a register.\n", indx); + return FALSE; + } + + if (GET_MODE (indx) != Pmode) + { + ADDR_INVALID ("Index is not in Pmode.\n", indx); + return FALSE; + } + + if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx)) + || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx))) + { + ADDR_INVALID ("Index is not valid.\n", indx); + return FALSE; + } + } + else if (scale) + abort (); /* scale w/o index invalid */ + + /* Validate scale factor: */ + if (scale) + { + HOST_WIDE_INT value; + + if (GET_CODE (scale) != CONST_INT) + { + ADDR_INVALID ("Scale is not valid.\n", scale); + return FALSE; + } + + value = INTVAL (scale); + if (value != 1 && value != 2 && value != 4 && value != 8) + { + ADDR_INVALID ("Scale is not a good multiplier.\n", scale); + return FALSE; + } + } + + /* Validate displacement. */ + if (disp) + { + if (!CONSTANT_ADDRESS_P (disp)) + { + ADDR_INVALID ("Displacement is not valid.\n", disp); + return FALSE; + } + + else if (GET_CODE (disp) == CONST_DOUBLE) + { + ADDR_INVALID ("Displacement is a const_double.\n", disp); + return FALSE; + } + + if (flag_pic && SYMBOLIC_CONST (disp)) + { + if (! legitimate_pic_address_disp_p (disp)) + { + ADDR_INVALID ("Displacement is an invalid PIC construct.\n", + disp); + return FALSE; + } + + if (base != pic_offset_table_rtx + && (indx != pic_offset_table_rtx || scale != NULL_RTX)) + { + ADDR_INVALID ("PIC displacement against invalid base.\n", disp); + return FALSE; + } + } + + else if (HALF_PIC_P ()) + { + if (! HALF_PIC_ADDRESS_P (disp) + || (base != NULL_RTX || indx != NULL_RTX)) + { + ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", + disp); + return FALSE; + } + } + } + + if (TARGET_DEBUG_ADDR) + fprintf (stderr, "Address is valid.\n"); + + /* Everything looks valid, return true */ + return TRUE; +} + +/* Return a legitimate reference for ORIG (an address) using the + register REG. If REG is 0, a new pseudo is generated. + + There are two types of references that must be handled: + + 1. Global data references must load the address from the GOT, via + the PIC reg. An insn is emitted to do this load, and the reg is + returned. + + 2. Static data references, constant pool addresses, and code labels + compute the address as an offset from the GOT, whose base is in + the PIC reg. Static data objects have SYMBOL_REF_FLAG set to + differentiate them from global data objects. The returned + address is the PIC reg + an unspec constant. + + GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC + reg also appears in the address. */ + +rtx +legitimize_pic_address (orig, reg) + rtx orig; + rtx reg; +{ + rtx addr = orig; + rtx new = orig; + rtx base; + + if (GET_CODE (addr) == LABEL_REF + || (GET_CODE (addr) == SYMBOL_REF + && (CONSTANT_POOL_ADDRESS_P (addr) + || SYMBOL_REF_FLAG (addr)))) + { + /* This symbol may be referenced via a displacement from the PIC + base address (@GOTOFF). */ + + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 7); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + else if (GET_CODE (addr) == SYMBOL_REF) + { + /* This symbol must be referenced via a load from the + Global Offset Table (@GOT). */ + + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 6); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + new = gen_rtx_MEM (Pmode, new); + RTX_UNCHANGING_P (new) = 1; + + if (reg == 0) + reg = gen_reg_rtx (Pmode); + emit_move_insn (reg, new); + new = reg; + } + else + { + if (GET_CODE (addr) == CONST) + { + addr = XEXP (addr, 0); + if (GET_CODE (addr) == UNSPEC) + { + /* Check that the unspec is one of the ones we generate? */ + } + else if (GET_CODE (addr) != PLUS) + abort(); + } + if (GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); + + /* Check first to see if this is a constant offset from a @GOTOFF + symbol reference. */ + if ((GET_CODE (op0) == LABEL_REF + || (GET_CODE (op0) == SYMBOL_REF + && (CONSTANT_POOL_ADDRESS_P (op0) + || SYMBOL_REF_FLAG (op0)))) + && GET_CODE (op1) == CONST_INT) + { + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), 7); + new = gen_rtx_PLUS (VOIDmode, new, op1); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + else + { + base = legitimize_pic_address (XEXP (addr, 0), reg); + new = legitimize_pic_address (XEXP (addr, 1), + base == reg ? NULL_RTX : reg); + + if (GET_CODE (new) == CONST_INT) + new = plus_constant (base, INTVAL (new)); + else + { + if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) + { + base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0)); + new = XEXP (new, 1); + } + new = gen_rtx_PLUS (Pmode, base, new); + } + } + } + } + return new; +} + +/* Emit insns to move operands[1] into operands[0]. */ + +void +emit_pic_move (operands, mode) + rtx *operands; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); + + if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])) + operands[1] = force_reg (Pmode, operands[1]); + else + operands[1] = legitimize_pic_address (operands[1], temp); +} + +/* 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 80386, we handle X+REG by loading X into a register R and + using R+REG. R will go in a general 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 a general reg. + + When -fpic is used, special handling is needed for symbolic references. + See comments by legitimize_pic_address in i386.c for details. */ + +rtx +legitimize_address (x, oldx, mode) + register rtx x; + register rtx oldx ATTRIBUTE_UNUSED; + enum machine_mode mode; +{ + int changed = 0; + unsigned log; + + if (TARGET_DEBUG_ADDR) + { + fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", + GET_MODE_NAME (mode)); + debug_rtx (x); + } + + if (flag_pic && SYMBOLIC_CONST (x)) + return legitimize_pic_address (x, 0); + + /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ + if (GET_CODE (x) == ASHIFT + && GET_CODE (XEXP (x, 1)) == CONST_INT + && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4) + { + changed = 1; + x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)), + GEN_INT (1 << log)); + } + + if (GET_CODE (x) == PLUS) + { + /* Canonicalize shifts by 0, 1, 2, 3 into multiply. */ + + if (GET_CODE (XEXP (x, 0)) == ASHIFT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4) + { + changed = 1; + XEXP (x, 0) = gen_rtx (MULT, Pmode, + force_reg (Pmode, XEXP (XEXP (x, 0), 0)), + GEN_INT (1 << log)); + } + + if (GET_CODE (XEXP (x, 1)) == ASHIFT + && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT + && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4) + { + changed = 1; + XEXP (x, 1) = gen_rtx (MULT, Pmode, + force_reg (Pmode, XEXP (XEXP (x, 1), 0)), + GEN_INT (1 << log)); + } + + /* Put multiply first if it isn't already. */ + if (GET_CODE (XEXP (x, 1)) == MULT) + { + rtx tmp = XEXP (x, 0); + XEXP (x, 0) = XEXP (x, 1); + XEXP (x, 1) = tmp; + changed = 1; + } + + /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const))) + into (plus (plus (mult (reg) (const)) (reg)) (const)). This can be + created by virtual register instantiation, register elimination, and + similar optimizations. */ + if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS) + { + changed = 1; + x = gen_rtx (PLUS, Pmode, + gen_rtx (PLUS, Pmode, XEXP (x, 0), + XEXP (XEXP (x, 1), 0)), + XEXP (XEXP (x, 1), 1)); + } + + /* Canonicalize + (plus (plus (mult (reg) (const)) (plus (reg) (const))) const) + into (plus (plus (mult (reg) (const)) (reg)) (const)). */ + else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT + && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS + && CONSTANT_P (XEXP (x, 1))) + { + rtx constant; + rtx other = NULL_RTX; + + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + constant = XEXP (x, 1); + other = XEXP (XEXP (XEXP (x, 0), 1), 1); + } + else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT) + { + constant = XEXP (XEXP (XEXP (x, 0), 1), 1); + other = XEXP (x, 1); + } + else + constant = 0; + + if (constant) + { + changed = 1; + x = gen_rtx (PLUS, Pmode, + gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0), + XEXP (XEXP (XEXP (x, 0), 1), 0)), + plus_constant (other, INTVAL (constant))); + } + } + + if (changed && legitimate_address_p (mode, x, FALSE)) + return x; + + if (GET_CODE (XEXP (x, 0)) == MULT) + { + changed = 1; + XEXP (x, 0) = force_operand (XEXP (x, 0), 0); + } + + if (GET_CODE (XEXP (x, 1)) == MULT) + { + changed = 1; + XEXP (x, 1) = force_operand (XEXP (x, 1), 0); + } + + if (changed + && GET_CODE (XEXP (x, 1)) == REG + && GET_CODE (XEXP (x, 0)) == REG) + return x; + + if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1))) + { + changed = 1; + x = legitimize_pic_address (x, 0); + } + + if (changed && legitimate_address_p (mode, x, FALSE)) + return x; + + if (GET_CODE (XEXP (x, 0)) == REG) + { + register rtx temp = gen_reg_rtx (Pmode); + register rtx val = force_operand (XEXP (x, 1), temp); + if (val != temp) + emit_move_insn (temp, val); + + XEXP (x, 1) = temp; + return x; + } + + else if (GET_CODE (XEXP (x, 1)) == REG) + { + register rtx temp = gen_reg_rtx (Pmode); + register rtx val = force_operand (XEXP (x, 0), temp); + if (val != temp) + emit_move_insn (temp, val); + + XEXP (x, 0) = temp; + return x; + } + } + + return x; +} + +/* Print an integer constant expression in assembler syntax. Addition + and subtraction are the only arithmetic that may appear in these + expressions. FILE is the stdio stream to write to, X is the rtx, and + CODE is the operand print code from the output string. */ + +static void +output_pic_addr_const (file, x, code) + FILE *file; + rtx x; + int code; +{ + char buf[256]; + + switch (GET_CODE (x)) + { + case PC: + if (flag_pic) + putc ('.', file); + else + abort (); + break; + + case SYMBOL_REF: + assemble_name (file, XSTR (x, 0)); + if (code == 'P' && ! SYMBOL_REF_FLAG (x)) + fputs ("@PLT", file); + break; + + case LABEL_REF: + x = XEXP (x, 0); + /* FALLTHRU */ + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); + assemble_name (asm_out_file, buf); + break; + + case CONST_INT: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + break; + + case CONST: + /* This used to output parentheses around the expression, + but that does not work on the 386 (either ATT or BSD assembler). */ + output_pic_addr_const (file, XEXP (x, 0), code); + break; + + case CONST_DOUBLE: + if (GET_MODE (x) == VOIDmode) + { + /* We can use %d if the number is <32 bits and positive. */ + if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) + fprintf (file, "0x%lx%08lx", + (unsigned long) CONST_DOUBLE_HIGH (x), + (unsigned long) CONST_DOUBLE_LOW (x)); + else + fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); + } + else + /* We can't handle floating point constants; + PRINT_OPERAND must handle them. */ + output_operand_lossage ("floating constant misused"); + break; + + case PLUS: + /* Some assemblers need integer constants to appear first. */ + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { + output_pic_addr_const (file, XEXP (x, 0), code); + fprintf (file, "+"); + output_pic_addr_const (file, XEXP (x, 1), code); + } + else if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + output_pic_addr_const (file, XEXP (x, 1), code); + fprintf (file, "+"); + output_pic_addr_const (file, XEXP (x, 0), code); + } + else + abort (); + break; + + case MINUS: + output_pic_addr_const (file, XEXP (x, 0), code); + fprintf (file, "-"); + output_pic_addr_const (file, XEXP (x, 1), code); + break; + + case UNSPEC: + if (XVECLEN (x, 0) != 1) + abort (); + output_pic_addr_const (file, XVECEXP (x, 0, 0), code); + switch (XINT (x, 1)) + { + case 6: + fputs ("@GOT", file); + break; + case 7: + fputs ("@GOTOFF", file); + break; + case 8: + fputs ("@PLT", file); + break; + default: + output_operand_lossage ("invalid UNSPEC as operand"); + break; + } + break; + + default: + output_operand_lossage ("invalid expression as operand"); + } +} + +static void +put_jump_code (code, reverse, file) + enum rtx_code code; + int reverse; + FILE *file; +{ + int flags = cc_prev_status.flags; + int ieee = (TARGET_IEEE_FP && (flags & CC_IN_80387)); + const char *suffix; + + if (flags & CC_Z_IN_NOT_C) + switch (code) + { + case EQ: + fputs (reverse ? "c" : "nc", file); + return; + + case NE: + fputs (reverse ? "nc" : "c", file); + return; + + default: + abort (); + } + if (ieee) + { + switch (code) + { + case LE: + suffix = reverse ? "ae" : "b"; + break; + case GT: + case LT: + case GE: + suffix = reverse ? "ne" : "e"; + break; + case EQ: + suffix = reverse ? "ne" : "e"; + break; + case NE: + suffix = reverse ? "e" : "ne"; + break; + default: + abort (); + } + fputs (suffix, file); + return; + } + if (flags & CC_TEST_AX) + abort(); + if ((flags & CC_NO_OVERFLOW) && (code == LE || code == GT)) + abort (); + if (reverse) + code = reverse_condition (code); + switch (code) + { + case EQ: + suffix = "e"; + break; + + case NE: + suffix = "ne"; + break; + + case GT: + suffix = flags & CC_IN_80387 ? "a" : "g"; + break; + + case GTU: + suffix = "a"; + break; + + case LT: + if (flags & CC_NO_OVERFLOW) + suffix = "s"; + else + suffix = flags & CC_IN_80387 ? "b" : "l"; + break; + + case LTU: + suffix = "b"; + break; + + case GE: + if (flags & CC_NO_OVERFLOW) + suffix = "ns"; + else + suffix = flags & CC_IN_80387 ? "ae" : "ge"; + break; + + case GEU: + suffix = "ae"; + break; + + case LE: + suffix = flags & CC_IN_80387 ? "be" : "le"; + break; + + case LEU: + suffix = "be"; + break; + + default: + abort (); + } + fputs (suffix, file); +} + +/* Append the correct conditional move suffix which corresponds to CODE. */ + +static void +put_condition_code (code, reverse_cc, mode, file) + enum rtx_code code; + int reverse_cc; + enum mode_class mode; + FILE * file; +{ + int ieee = (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)); + if (reverse_cc && ! ieee) + code = reverse_condition (code); + + if (mode == MODE_INT) + switch (code) + { + case NE: + if (cc_prev_status.flags & CC_Z_IN_NOT_C) + fputs ("b", file); + else + fputs ("ne", file); + return; + + case EQ: + if (cc_prev_status.flags & CC_Z_IN_NOT_C) + fputs ("ae", file); + else + fputs ("e", file); + return; + + case GE: + if (cc_prev_status.flags & CC_NO_OVERFLOW) + fputs ("ns", file); + else + fputs ("ge", file); + return; + + case GT: + fputs ("g", file); + return; + + case LE: + fputs ("le", file); + return; + + case LT: + if (cc_prev_status.flags & CC_NO_OVERFLOW) + fputs ("s", file); + else + fputs ("l", file); + return; + + case GEU: + fputs ("ae", file); + return; + + case GTU: + fputs ("a", file); + return; + + case LEU: + fputs ("be", file); + return; + + case LTU: + fputs ("b", file); + return; + + default: + output_operand_lossage ("Invalid %%C operand"); + } + + else if (mode == MODE_FLOAT) + switch (code) + { + case NE: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file); + return; + case EQ: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file); + return; + case GE: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file); + return; + case GT: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file); + return; + case LE: + fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file); + return; + case LT: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file); + return; + case GEU: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file); + return; + case GTU: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file); + return; + case LEU: + fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file); + return; + case LTU: + fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file); + return; + default: + output_operand_lossage ("Invalid %%C operand"); + } +} + +/* Meaning of CODE: + L,W,B,Q,S,T -- print the opcode suffix for specified size of operand. + C -- print opcode suffix for set/cmov insn. + c -- like C, but print reversed condition + F -- print opcode suffix for fcmov insn. + f -- like F, but print reversed condition + D -- print the opcode suffix for a jump + d -- like D, but print reversed condition + R -- print the prefix for register names. + z -- print the opcode suffix for the size of the current operand. + * -- print a star (in certain assembler syntax) + w -- print the operand as if it's a "word" (HImode) even if it isn't. + J -- print the appropriate jump operand. + s -- print a shift double count, followed by the assemblers argument + delimiter. + b -- print the QImode name of the register for the indicated operand. + %b0 would print %al if operands[0] is reg 0. + w -- likewise, print the HImode name of the register. + k -- likewise, print the SImode name of the register. + h -- print the QImode name for a "high" register, either ah, bh, ch or dh. + y -- print "st(0)" instead of "st" as a register. + P -- print as a PIC constant + _ -- output "_" if YES_UNDERSCORES */ + +void +print_operand (file, x, code) + FILE *file; + rtx x; + int code; +{ + if (code) + { + switch (code) + { + case '*': + if (USE_STAR) + putc ('*', file); + return; + + case '_': +#ifdef YES_UNDERSCORES + putc ('_', file); +#endif + return; + + case 'L': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'W': + PUT_OP_SIZE (code, 'w', file); + return; + + case 'B': + PUT_OP_SIZE (code, 'b', file); + return; + + case 'Q': + PUT_OP_SIZE (code, 'l', file); + return; + + case 'S': + PUT_OP_SIZE (code, 's', file); + return; + + case 'T': + PUT_OP_SIZE (code, 't', file); + return; + + case 'z': + /* 387 opcodes don't get size suffixes if the operands are + registers. */ + + if (STACK_REG_P (x)) + return; + + /* this is the size of op from size of operand */ + switch (GET_MODE_SIZE (GET_MODE (x))) + { + case 2: +#ifdef HAVE_GAS_FILDS_FISTS + PUT_OP_SIZE ('W', 's', file); +#endif + return; + + case 4: + if (GET_MODE (x) == SFmode) + { + PUT_OP_SIZE ('S', 's', file); + return; + } + else + PUT_OP_SIZE ('L', 'l', file); + return; + + case 12: + PUT_OP_SIZE ('T', 't', file); + return; + + case 8: + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) + { +#ifdef GAS_MNEMONICS + PUT_OP_SIZE ('Q', 'q', file); + return; +#else + PUT_OP_SIZE ('Q', 'l', file); /* Fall through */ +#endif + } + + PUT_OP_SIZE ('Q', 'l', file); + return; + + default: + abort (); + } + + case 'b': + case 'w': + case 'k': + case 'h': + case 'y': + case 'P': + case 'X': + break; + + case 'J': + switch (GET_CODE (x)) + { + /* These conditions are appropriate for testing the result + of an arithmetic operation, not for a compare operation. + Cases GE, LT assume CC_NO_OVERFLOW true. All cases assume + CC_Z_IN_NOT_C false and not floating point. */ + case NE: fputs ("jne", file); return; + case EQ: fputs ("je", file); return; + case GE: fputs ("jns", file); return; + case LT: fputs ("js", file); return; + case GEU: fputs ("jmp", file); return; + case GTU: fputs ("jne", file); return; + case LEU: fputs ("je", file); return; + case LTU: fputs ("#branch never", file); return; + + /* no matching branches for GT nor LE */ + + default: + abort (); + } + + case 's': + if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT) + { + PRINT_OPERAND (file, x, 0); + fputs (AS2C (,) + 1, file); + } + + return; + + case 'D': + put_jump_code (GET_CODE (x), 0, file); + return; + + case 'd': + put_jump_code (GET_CODE (x), 1, file); + return; + + /* This is used by the conditional move instructions. */ + case 'C': + put_condition_code (GET_CODE (x), 0, MODE_INT, file); + return; + + /* Like above, but reverse condition */ + case 'c': + put_condition_code (GET_CODE (x), 1, MODE_INT, file); return; + + case 'F': + put_condition_code (GET_CODE (x), 0, MODE_FLOAT, file); + return; + + /* Like above, but reverse condition */ + case 'f': + put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file); + return; + + default: + { + char str[50]; + + sprintf (str, "invalid operand code `%c'", code); + output_operand_lossage (str); + } + } + } + + if (GET_CODE (x) == REG) + { + PRINT_REG (x, code, file); + } + + else if (GET_CODE (x) == MEM) + { + PRINT_PTR (x, file); + if (CONSTANT_ADDRESS_P (XEXP (x, 0))) + { + if (flag_pic) + output_pic_addr_const (file, XEXP (x, 0), code); + else + output_addr_const (file, XEXP (x, 0)); + } + else + 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); + PRINT_IMMED_PREFIX (file); + fprintf (file, "0x%lx", l); + } + + /* These float cases don't actually occur as immediate operands. */ + 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, "%.22e", dstr); + fprintf (file, "%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, "%.22e", dstr); + fprintf (file, "%s", dstr); + } + else + { + if (code != 'P') + { + if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) + PRINT_IMMED_PREFIX (file); + else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == LABEL_REF) + PRINT_OFFSET_PREFIX (file); + } + if (flag_pic) + output_pic_addr_const (file, x, code); + else + output_addr_const (file, x); + } +} + +/* Print a memory operand whose address is ADDR. */ + +void +print_operand_address (file, addr) + FILE *file; + register rtx addr; +{ + register rtx reg1, reg2, breg, ireg; + rtx offset; + + switch (GET_CODE (addr)) + { + case REG: + /* ESI addressing makes instruction vector decoded on the K6. We can + avoid this by ESI+0 addressing. */ + if (REGNO_REG_CLASS (REGNO (addr)) == SIREG + && ix86_cpu == PROCESSOR_K6 && !optimize_size) + output_addr_const (file, const0_rtx); + ADDR_BEG (file); + fprintf (file, "%se", RP); + fputs (hi_reg_name[REGNO (addr)], file); + ADDR_END (file); + 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)) == MULT) + reg1 = XEXP (addr, 0), addr = XEXP (addr, 1); + else if (GET_CODE (XEXP (addr, 1)) == MULT) + reg1 = XEXP (addr, 1), addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 0)) == REG) + reg1 = XEXP (addr, 0), addr = XEXP (addr, 1); + else if (GET_CODE (XEXP (addr, 1)) == REG) + reg1 = XEXP (addr, 1), addr = XEXP (addr, 0); + + if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) + { + if (reg1 == 0) + reg1 = addr; + else + reg2 = addr; + + addr = 0; + } + + if (offset != 0) + { + if (addr != 0) + abort (); + addr = offset; + } + + if ((reg1 && 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) + { + int scale = 1; + + if (addr != 0) + { + if (flag_pic) + output_pic_addr_const (file, addr, 0); + else if (GET_CODE (addr) == LABEL_REF) + output_asm_label (addr); + else + output_addr_const (file, addr); + } + + if (ireg != 0 && GET_CODE (ireg) == MULT) + { + scale = INTVAL (XEXP (ireg, 1)); + ireg = XEXP (ireg, 0); + } + + /* The stack pointer can only appear as a base register, + never an index register, so exchange the regs if it is wrong. */ + + if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM) + { + rtx tmp; + + tmp = breg; + breg = ireg; + ireg = tmp; + } + + /* output breg+ireg*scale */ + PRINT_B_I_S (breg, ireg, scale, file); + break; + } + + case MULT: + { + int scale; + + if (GET_CODE (XEXP (addr, 0)) == CONST_INT) + { + scale = INTVAL (XEXP (addr, 0)); + ireg = XEXP (addr, 1); + } + else + { + scale = INTVAL (XEXP (addr, 1)); + ireg = XEXP (addr, 0); + } + + /* (reg,reg,) is shorter than (,reg,2). */ + if (scale == 2) + { + PRINT_B_I_S (ireg, ireg, 1, file); + } + else + { + output_addr_const (file, const0_rtx); + PRINT_B_I_S (NULL_RTX, ireg, scale, file); + } + } + break; + + default: + if (GET_CODE (addr) == CONST_INT + && INTVAL (addr) < 0x8000 + && INTVAL (addr) >= -0x8000) + fprintf (file, "%d", (int) INTVAL (addr)); + else + { + if (flag_pic) + output_pic_addr_const (file, addr, 0); + else + output_addr_const (file, addr); + } + } +} + +/* Set the cc_status for the results of an insn whose pattern is EXP. + On the 80386, we assume that only test and compare insns, as well + as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, BSF, ASHIFT, + ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully. + Also, we assume that jumps, moves and sCOND don't affect the condition + codes. All else clobbers the condition codes, by assumption. + + We assume that ALL integer add, minus, etc. instructions effect the + condition codes. This MUST be consistent with i386.md. + + We don't record any float test or compare - the redundant test & + compare check in final.c does not handle stack-like regs correctly. */ + +void +notice_update_cc (exp) + rtx exp; +{ + if (GET_CODE (exp) == SET) + { + /* Jumps do not alter the cc's. */ + if (SET_DEST (exp) == pc_rtx) + return; + + /* Moving register or memory into a register: + it doesn't alter the cc's, but it might invalidate + the RTX's which we remember the cc's came from. + (Note that moving a constant 0 or 1 MAY set the cc's). */ + if (REG_P (SET_DEST (exp)) + && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM + || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<' + || GET_CODE (SET_SRC (exp)) == IF_THEN_ELSE)) + { + if (cc_status.value1 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) + cc_status.value1 = 0; + + if (cc_status.value2 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) + cc_status.value2 = 0; + + return; + } + + /* Moving register into memory doesn't alter the cc's. + It may invalidate the RTX's which we remember the cc's came from. */ + if (GET_CODE (SET_DEST (exp)) == MEM + && (REG_P (SET_SRC (exp)) + || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<')) + { + if (cc_status.value1 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)) + cc_status.value1 = 0; + if (cc_status.value2 + && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)) + cc_status.value2 = 0; + + return; + } + + /* Function calls clobber the cc's. */ + else if (GET_CODE (SET_SRC (exp)) == CALL) + { + CC_STATUS_INIT; + return; + } + + /* Tests and compares set the cc's in predictable ways. */ + else if (SET_DEST (exp) == cc0_rtx) + { + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (exp); + return; + } + + /* Certain instructions effect the condition codes. */ + else if (GET_MODE (SET_SRC (exp)) == SImode + || GET_MODE (SET_SRC (exp)) == HImode + || GET_MODE (SET_SRC (exp)) == QImode) + switch (GET_CODE (SET_SRC (exp))) + { + case ASHIFTRT: case LSHIFTRT: case ASHIFT: + /* Shifts on the 386 don't set the condition codes if the + shift count is zero. */ + if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT) + { + CC_STATUS_INIT; + break; + } + + /* We assume that the CONST_INT is non-zero (this rtx would + have been deleted if it were zero. */ + + case PLUS: case MINUS: case NEG: + case AND: case IOR: case XOR: + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_SRC (exp); + cc_status.value2 = SET_DEST (exp); + break; + + /* This is the bsf pattern used by ffs. */ + case UNSPEC: + if (XINT (SET_SRC (exp), 1) == 5) + { + /* Only the Z flag is defined after bsf. */ + cc_status.flags + = CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW; + cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0); + cc_status.value2 = 0; + break; + } + /* FALLTHRU */ + + default: + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } + } + else if (GET_CODE (exp) == PARALLEL + && GET_CODE (XVECEXP (exp, 0, 0)) == SET) + { + if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) + return; + if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) + + { + CC_STATUS_INIT; + if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0)))) + { + cc_status.flags |= CC_IN_80387; + if (0 && TARGET_CMOVE && stack_regs_mentioned_p + (XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1))) + cc_status.flags |= CC_FCOMI; + } + else + cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); + return; + } + + CC_STATUS_INIT; + } + else + { + CC_STATUS_INIT; + } +} + +/* Split one or more DImode RTL references into pairs of SImode + references. The RTL can be REG, offsettable MEM, integer constant, or + CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to + split and "num" is its length. lo_half and hi_half are output arrays + that parallel "operands". */ + +void +split_di (operands, num, lo_half, hi_half) + rtx operands[]; + int num; + rtx lo_half[], hi_half[]; +{ + while (num--) + { + rtx op = operands[num]; + if (! reload_completed) + { + lo_half[num] = gen_lowpart (SImode, op); + hi_half[num] = gen_highpart (SImode, op); + } + else if (GET_CODE (op) == REG) + { + lo_half[num] = gen_rtx_REG (SImode, REGNO (op)); + hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1); + } + else if (CONSTANT_P (op)) + split_double (op, &lo_half[num], &hi_half[num]); + else if (offsettable_memref_p (op)) + { + rtx lo_addr = XEXP (op, 0); + rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0); + lo_half[num] = change_address (op, SImode, lo_addr); + hi_half[num] = change_address (op, SImode, hi_addr); + } + else + abort(); + } +} + +/* Return 1 if this is a valid binary operation on a 387. + OP is the expression matched, and MODE is its mode. */ + +int +binary_387_op (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + switch (GET_CODE (op)) + { + case PLUS: + case MINUS: + case MULT: + case DIV: + return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; + + default: + return 0; + } +} + +/* Return 1 if this is a valid shift or rotate operation on a 386. + OP is the expression matched, and MODE is its mode. */ + +int +shift_op (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx operand = XEXP (op, 0); + + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + + if (GET_MODE (operand) != GET_MODE (op) + || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT) + return 0; + + return (GET_CODE (op) == ASHIFT + || GET_CODE (op) == ASHIFTRT + || GET_CODE (op) == LSHIFTRT + || GET_CODE (op) == ROTATE + || GET_CODE (op) == ROTATERT); +} + +/* Return 1 if OP is COMPARE rtx with mode VOIDmode. + MODE is not used. */ + +int +VOIDmode_compare_op (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode; +} + +/* Output code to perform a 387 binary operation in INSN, one of PLUS, + MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3] + is the expression of the binary operation. The output may either be + emitted here, or returned to the caller, like all output_* functions. + + There is no guarantee that the operands are the same mode, as they + might be within FLOAT or FLOAT_EXTEND expressions. */ + +char * +output_387_binary_op (insn, operands) + rtx insn; + rtx *operands; +{ + rtx temp; + char *base_op; + static char buf[100]; + + switch (GET_CODE (operands[3])) + { + case PLUS: + base_op = "fadd"; + break; + + case MINUS: + base_op = "fsub"; + break; + + case MULT: + base_op = "fmul"; + break; + + case DIV: + base_op = "fdiv"; + break; + + default: + abort (); + } + + strcpy (buf, base_op); + + switch (GET_CODE (operands[3])) + { + case MULT: + case PLUS: + if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) + { + temp = operands[2]; + operands[2] = operands[1]; + operands[1] = temp; + } + + if (GET_CODE (operands[2]) == MEM) + return strcat (buf, AS1 (%z2,%2)); + + if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) + abort (); + + if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) + { + if (STACK_TOP_P (operands[0])) + return strcat (buf, AS2 (p,%0,%2)); + else + return strcat (buf, AS2 (p,%2,%0)); + } + + if (STACK_TOP_P (operands[0])) + return strcat (buf, AS2C (%y2,%0)); + else + return strcat (buf, AS2C (%2,%0)); + + case MINUS: + case DIV: + if (GET_CODE (operands[1]) == MEM) + return strcat (buf, AS1 (r%z1,%1)); + + if (GET_CODE (operands[2]) == MEM) + return strcat (buf, AS1 (%z2,%2)); + + if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) + abort (); + + if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) + { + if (STACK_TOP_P (operands[0])) + return strcat (buf, AS2 (p,%0,%2)); + else + return strcat (buf, AS2 (rp,%2,%0)); + } + + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + { + if (STACK_TOP_P (operands[0])) + return strcat (buf, AS2 (rp,%0,%1)); + else + return strcat (buf, AS2 (p,%1,%0)); + } + + if (STACK_TOP_P (operands[0])) + { + if (STACK_TOP_P (operands[1])) + return strcat (buf, AS2C (%y2,%0)); + else + return strcat (buf, AS2 (r,%y1,%0)); + } + else if (STACK_TOP_P (operands[1])) + return strcat (buf, AS2C (%1,%0)); + else + return strcat (buf, AS2 (r,%2,%0)); + + default: + abort (); + } +} + +/* Output code for INSN to convert a float to a signed int. OPERANDS + are the insn operands. The input may be SFmode, DFmode, or XFmode + and the output operand may be SImode or DImode. As a special case, + make sure that the 387 stack top dies if the output mode is DImode, + because the hardware requires this. */ + +char * +output_fix_trunc (insn, operands) + rtx insn; + rtx *operands; +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + rtx xops[2]; + + if (! STACK_TOP_P (operands[1])) + abort (); + + if (GET_MODE (operands[0]) == DImode && ! stack_top_dies) + abort (); + + xops[0] = GEN_INT (0x0c00); + xops[1] = operands[5]; + + output_asm_insn (AS1 (fnstc%W2,%2), operands); + output_asm_insn (AS2 (mov%W5,%2,%w5), operands); + output_asm_insn (AS2 (or%W1,%0,%w1), xops); + output_asm_insn (AS2 (mov%W3,%w5,%3), operands); + output_asm_insn (AS1 (fldc%W3,%3), operands); + + xops[0] = NON_STACK_REG_P (operands[0]) ? operands[4] : operands[0]; + + if (stack_top_dies) + output_asm_insn (AS1 (fistp%z0,%y0), xops); + else + output_asm_insn (AS1 (fist%z0,%y0), xops); + + if (NON_STACK_REG_P (operands[0])) + { + if (GET_MODE (operands[0]) == SImode) + output_asm_insn (AS2 (mov%L0,%4,%0), operands); + else + { + xops[0] = operands[0]; + xops[1] = operands[4]; + output_asm_insn (output_move_double (xops), xops); + } + } + + return AS1 (fldc%W2,%2); +} + +/* Output code for INSN to extend a float. OPERANDS are the insn + operands. The output may be DFmode or XFmode and the input operand + may be SFmode or DFmode. Operands 2 and 3 are scratch memory and + are only necessary if operands 0 or 1 are non-stack registers. */ + +void +output_float_extend (insn, operands) + rtx insn; + rtx *operands; +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + rtx xops[2]; + + if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1])) + abort (); + + if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies) + return; + + if (STACK_TOP_P (operands[0]) ) + { + if (NON_STACK_REG_P (operands[1])) + { + if (GET_MODE (operands[1]) == SFmode) + output_asm_insn (AS2 (mov%L0,%1,%2), operands); + else + { + xops[0] = operands[2]; + xops[1] = operands[1]; + output_asm_insn (output_move_double (xops), xops); + } + } + + xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1]; + + output_asm_insn (AS1 (fld%z0,%y0), xops); + } + else + { + xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0]; + + if (stack_top_dies + || (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode)) + { + output_asm_insn (AS1 (fstp%z0,%y0), xops); + if (! stack_top_dies) + output_asm_insn (AS1 (fld%z0,%y0), xops); + } + else + output_asm_insn (AS1 (fst%z0,%y0), xops); + + if (NON_STACK_REG_P (operands[0])) + { + xops[0] = operands[0]; + xops[1] = operands[3]; + output_asm_insn (output_move_double (xops), xops); + } + } +} + +/* Output code for INSN to compare OPERANDS. The two operands might + not have the same mode: one might be within a FLOAT or FLOAT_EXTEND + expression. If the compare is in mode CCFPEQmode, use an opcode that + will not fault if a qNaN is present. */ + +char * +output_float_compare (insn, operands) + rtx insn; + rtx *operands; +{ + int stack_top_dies; + rtx body = XVECEXP (PATTERN (insn), 0, 0); + int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode; + rtx tmp; + int cc0_set = 1; + int i; + + if (0 && TARGET_CMOVE && STACK_REG_P (operands[1])) + { + cc_status.flags |= CC_FCOMI; + cc_prev_status.flags &= ~CC_TEST_AX; + } + + if (! STACK_TOP_P (operands[0])) + { + tmp = operands[0]; + operands[0] = operands[1]; + operands[1] = tmp; + cc_status.flags |= CC_REVERSED; + } + + if (! STACK_TOP_P (operands[0])) + abort (); + + stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (STACK_REG_P (operands[1]) + && stack_top_dies + && find_regno_note (insn, REG_DEAD, REGNO (operands[1])) + && REGNO (operands[1]) == FIRST_STACK_REG + 1) + { + /* If both the top of the 387 stack dies, and the other operand + is also a stack register that dies, then this must be a + `fcompp' float compare */ + + if (unordered_compare) + { + if (cc_status.flags & CC_FCOMI) + { + output_asm_insn (AS2 (fucomip,%y1,%0), operands); + output_asm_insn (AS1 (fstp, %y0), operands); + cc0_set = 0; + } + else + output_asm_insn ("fucompp", operands); + } + else + { + if (cc_status.flags & CC_FCOMI) + { + output_asm_insn (AS2 (fcomip, %y1,%0), operands); + output_asm_insn (AS1 (fstp, %y0), operands); + cc0_set = 0; + } + else + output_asm_insn ("fcompp", operands); + } + } + else + { + static char buf[100]; + + /* Decide if this is a float compare or an unordered float compare. */ + + if (unordered_compare) + strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom"); + else + strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom"); + + /* Modify the opcode if the 387 stack is to be popped. */ + + if (stack_top_dies) + strcat (buf, "p"); + + if (cc_status.flags & CC_FCOMI) + { + output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands); + cc0_set = 0; + } + else + output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands); + } + + /* Now retrieve the condition code. */ + if (cc0_set) + { + char *r = output_fp_cc0_set (insn); + if (r[0]) output_asm_insn (r, operands); + } + + + /* We emit fstp instruction after integer comparsions to improve + scheduling. */ + for (i = 0; i < 2 ; i++) + { + if (STACK_REG_P (operands[i]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) + && REGNO (operands[i]) != FIRST_STACK_REG + && (!stack_top_dies || REGNO (operands[i]) != FIRST_STACK_REG + 1)) + { + rtx xexp[i]; + xexp[0] = gen_rtx_REG (DFmode, + REGNO (operands[i]) - (stack_top_dies != 0)); + output_asm_insn (AS1 (fstp, %y0), xexp); + } + } + + return ""; + + +} + +/* Output opcodes to transfer the results of FP compare or test INSN + from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the + result of the compare or test is unordered, no comparison operator + succeeds except NE. Return an output template, if any. */ + +char * +output_fp_cc0_set (insn) + rtx insn; +{ + rtx xops[3]; + rtx next; + enum rtx_code code; + + xops[0] = gen_rtx_REG (HImode, 0); + output_asm_insn (AS1 (fnsts%W0,%0), xops); + + if (! TARGET_IEEE_FP) + { + if (!(cc_status.flags & CC_REVERSED)) + { + next = next_cc0_user (insn); + + if (GET_CODE (next) == JUMP_INSN + && GET_CODE (PATTERN (next)) == SET + && SET_DEST (PATTERN (next)) == pc_rtx + && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) + code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); + else if (GET_CODE (PATTERN (next)) == SET) + code = GET_CODE (SET_SRC (PATTERN (next))); + else + return "sahf"; + + if (code == GT || code == LT || code == EQ || code == NE + || code == LE || code == GE) + { + /* We will test eax directly. */ + cc_status.flags |= CC_TEST_AX; + return ""; + } + } + + return "sahf"; + } + + next = next_cc0_user (insn); + if (next == NULL_RTX) + abort (); + + if (GET_CODE (next) == JUMP_INSN + && GET_CODE (PATTERN (next)) == SET + && SET_DEST (PATTERN (next)) == pc_rtx + && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) + code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); + else if (GET_CODE (PATTERN (next)) == SET) + { + if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) + code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); + else + code = GET_CODE (SET_SRC (PATTERN (next))); + } + + else if (GET_CODE (PATTERN (next)) == PARALLEL + && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET) + { + if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE) + code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0)); + else + code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))); + } + else + abort (); + + xops[0] = gen_rtx_REG (QImode, 0); + + switch (code) + { + case GT: + xops[1] = GEN_INT (0x45); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + /* je label */ + break; + + case LT: + xops[1] = GEN_INT (0x45); + xops[2] = GEN_INT (0x01); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); + /* je label */ + break; + + case GE: + xops[1] = GEN_INT (0x05); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + /* je label */ + break; + + case LE: + xops[1] = GEN_INT (0x45); + xops[2] = GEN_INT (0x40); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + output_asm_insn (AS1 (dec%B0,%h0), xops); + output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); + /* jb label */ + break; + + case EQ: + xops[1] = GEN_INT (0x45); + xops[2] = GEN_INT (0x40); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + output_asm_insn (AS2 (cmp%B0,%2,%h0), xops); + /* je label */ + break; + + case NE: + xops[1] = GEN_INT (0x44); + xops[2] = GEN_INT (0x40); + output_asm_insn (AS2 (and%B0,%1,%h0), xops); + output_asm_insn (AS2 (xor%B0,%2,%h0), xops); + /* jne label */ + break; + + case GTU: + case LTU: + case GEU: + case LEU: + default: + abort (); + } + + return ""; +} + +#define MAX_386_STACK_LOCALS 2 + +static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; + +/* Define the structure for the machine field in struct function. */ +struct machine_function +{ + rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; + rtx pic_label_rtx; + char pic_label_name[256]; +}; + +/* Functions to save and restore i386_stack_locals. + These will be called, via pointer variables, + from push_function_context and pop_function_context. */ + +void +save_386_machine_status (p) + struct function *p; +{ + p->machine + = (struct machine_function *) xmalloc (sizeof (struct machine_function)); + bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals, + sizeof i386_stack_locals); + p->machine->pic_label_rtx = pic_label_rtx; + bcopy (pic_label_name, p->machine->pic_label_name, 256); +} + +void +restore_386_machine_status (p) + struct function *p; +{ + bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals, + sizeof i386_stack_locals); + pic_label_rtx = p->machine->pic_label_rtx; + bcopy (p->machine->pic_label_name, pic_label_name, 256); + free (p->machine); + p->machine = NULL; +} + +/* Clear stack slot assignments remembered from previous functions. + This is called from INIT_EXPANDERS once before RTL is emitted for each + function. */ + +void +clear_386_stack_locals () +{ + enum machine_mode mode; + int n; + + for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; + mode = (enum machine_mode) ((int) mode + 1)) + for (n = 0; n < MAX_386_STACK_LOCALS; n++) + i386_stack_locals[(int) mode][n] = NULL_RTX; + + pic_label_rtx = NULL_RTX; + bzero (pic_label_name, 256); + /* Arrange to save and restore i386_stack_locals around nested functions. */ + save_machine_status = save_386_machine_status; + restore_machine_status = restore_386_machine_status; +} + +/* Return a MEM corresponding to a stack slot with mode MODE. + Allocate a new slot if necessary. + + The RTL for a function can have several slots available: N is + which slot to use. */ + +rtx +assign_386_stack_local (mode, n) + enum machine_mode mode; + int n; +{ + if (n < 0 || n >= MAX_386_STACK_LOCALS) + abort (); + + if (i386_stack_locals[(int) mode][n] == NULL_RTX) + i386_stack_locals[(int) mode][n] + = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); + + return i386_stack_locals[(int) mode][n]; +} + +int is_mul(op,mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == MULT); +} + +int is_div(op,mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == DIV); +} + +#ifdef NOTYET +/* Create a new copy of an rtx. + Recursively copies the operands of the rtx, + except for those few rtx codes that are sharable. + Doesn't share CONST */ + +rtx +copy_all_rtx (orig) + register rtx orig; +{ + register rtx copy; + register int i, j; + register RTX_CODE code; + register char *format_ptr; + + code = GET_CODE (orig); + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case SCRATCH: + /* SCRATCH must be shared because they represent distinct values. */ + return orig; + +#if 0 + case CONST: + /* CONST can be shared if it contains a SYMBOL_REF. If it contains + a LABEL_REF, it isn't sharable. */ + if (GET_CODE (XEXP (orig, 0)) == PLUS + && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF + && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT) + return orig; + break; +#endif + /* A MEM with a constant address is not sharable. The problem is that + the constant address may need to be reloaded. If the mem is shared, + then reloading one copy of this mem will cause all copies to appear + to have been reloaded. */ + } + + copy = rtx_alloc (code); + PUT_MODE (copy, GET_MODE (orig)); + copy->in_struct = orig->in_struct; + copy->volatil = orig->volatil; + copy->unchanging = orig->unchanging; + copy->integrated = orig->integrated; + /* intel1 */ + copy->is_spill_rtx = orig->is_spill_rtx; + + format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); + + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) + { + switch (*format_ptr++) + { + case 'e': + XEXP (copy, i) = XEXP (orig, i); + if (XEXP (orig, i) != NULL) + XEXP (copy, i) = copy_rtx (XEXP (orig, i)); + break; + + case '0': + case 'u': + XEXP (copy, i) = XEXP (orig, i); + break; + + case 'E': + case 'V': + XVEC (copy, i) = XVEC (orig, i); + if (XVEC (orig, i) != NULL) + { + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); + for (j = 0; j < XVECLEN (copy, i); j++) + XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j)); + } + break; + + case 'w': + XWINT (copy, i) = XWINT (orig, i); + break; + + case 'i': + XINT (copy, i) = XINT (orig, i); + break; + + case 's': + case 'S': + XSTR (copy, i) = XSTR (orig, i); + break; + + default: + abort (); + } + } + return copy; +} + + +/* Try to rewrite a memory address to make it valid */ + +void +rewrite_address (mem_rtx) + rtx mem_rtx; +{ + rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx; + int scale = 1; + int offset_adjust = 0; + int was_only_offset = 0; + rtx mem_addr = XEXP (mem_rtx, 0); + char *storage = oballoc (0); + int in_struct = 0; + int is_spill_rtx = 0; + + in_struct = MEM_IN_STRUCT_P (mem_rtx); + is_spill_rtx = RTX_IS_SPILL_P (mem_rtx); + + if (GET_CODE (mem_addr) == PLUS + && GET_CODE (XEXP (mem_addr, 1)) == PLUS + && GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG) + { + /* This part is utilized by the combiner. */ + ret_rtx + = gen_rtx (PLUS, GET_MODE (mem_addr), + gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)), + XEXP (mem_addr, 0), XEXP (XEXP (mem_addr, 1), 0)), + XEXP (XEXP (mem_addr, 1), 1)); + + if (memory_address_p (GET_MODE (mem_rtx), ret_rtx)) + { + XEXP (mem_rtx, 0) = ret_rtx; + RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx; + return; + } + + obfree (storage); + } + + /* This part is utilized by loop.c. + If the address contains PLUS (reg,const) and this pattern is invalid + in this case - try to rewrite the address to make it valid. */ + storage = oballoc (0); + index_rtx = base_rtx = offset_rtx = NULL; + + /* Find the base index and offset elements of the memory address. */ + if (GET_CODE (mem_addr) == PLUS) + { + if (GET_CODE (XEXP (mem_addr, 0)) == REG) + { + if (GET_CODE (XEXP (mem_addr, 1)) == REG) + base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0); + else + base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1); + } + + else if (GET_CODE (XEXP (mem_addr, 0)) == MULT) + { + index_rtx = XEXP (mem_addr, 0); + if (GET_CODE (XEXP (mem_addr, 1)) == REG) + base_rtx = XEXP (mem_addr, 1); + else + offset_rtx = XEXP (mem_addr, 1); + } + + else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS) + { + if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS + && GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT + && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0)) + == REG) + && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1)) + == CONST_INT) + && (GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1)) + == CONST_INT) + && GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG + && GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF) + { + index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0); + offset_rtx = XEXP (mem_addr, 1); + base_rtx = XEXP (XEXP (mem_addr, 0), 1); + offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1)); + } + else + { + offset_rtx = XEXP (mem_addr, 1); + index_rtx = XEXP (XEXP (mem_addr, 0), 0); + base_rtx = XEXP (XEXP (mem_addr, 0), 1); + } + } + + else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT) + { + was_only_offset = 1; + index_rtx = NULL; + base_rtx = NULL; + offset_rtx = XEXP (mem_addr, 1); + offset_adjust = INTVAL (XEXP (mem_addr, 0)); + if (offset_adjust == 0) + { + XEXP (mem_rtx, 0) = offset_rtx; + RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx; + return; + } + } + else + { + obfree (storage); + return; + } + } + else if (GET_CODE (mem_addr) == MULT) + index_rtx = mem_addr; + else + { + obfree (storage); + return; + } + + if (index_rtx != 0 && GET_CODE (index_rtx) == MULT) + { + if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT) + { + obfree (storage); + return; + } + + scale_rtx = XEXP (index_rtx, 1); + scale = INTVAL (scale_rtx); + index_rtx = copy_all_rtx (XEXP (index_rtx, 0)); + } + + /* Now find which of the elements are invalid and try to fix them. */ + if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL) + { + offset_adjust = INTVAL (index_rtx) * scale; + + if (offset_rtx != 0 && CONSTANT_P (offset_rtx)) + offset_rtx = plus_constant (offset_rtx, offset_adjust); + else if (offset_rtx == 0) + offset_rtx = const0_rtx; + + RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx; + XEXP (mem_rtx, 0) = offset_rtx; + return; + } + + if (base_rtx && GET_CODE (base_rtx) == PLUS + && GET_CODE (XEXP (base_rtx, 0)) == REG + && GET_CODE (XEXP (base_rtx, 1)) == CONST_INT) + { + offset_adjust += INTVAL (XEXP (base_rtx, 1)); + base_rtx = copy_all_rtx (XEXP (base_rtx, 0)); + } + + else if (base_rtx && GET_CODE (base_rtx) == CONST_INT) + { + offset_adjust += INTVAL (base_rtx); + base_rtx = NULL; + } + + if (index_rtx && GET_CODE (index_rtx) == PLUS + && GET_CODE (XEXP (index_rtx, 0)) == REG + && GET_CODE (XEXP (index_rtx, 1)) == CONST_INT) + { + offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale; + index_rtx = copy_all_rtx (XEXP (index_rtx, 0)); + } + + if (index_rtx) + { + if (! LEGITIMATE_INDEX_P (index_rtx) + && ! (index_rtx == stack_pointer_rtx && scale == 1 + && base_rtx == NULL)) + { + obfree (storage); + return; + } + } + + if (base_rtx) + { + if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG) + { + obfree (storage); + return; + } + } + + if (offset_adjust != 0) + { + if (offset_rtx != 0 && CONSTANT_P (offset_rtx)) + offset_rtx = plus_constant (offset_rtx, offset_adjust); + else + offset_rtx = const0_rtx; + + if (index_rtx) + { + if (base_rtx) + { + if (scale != 1) + { + ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), + gen_rtx (MULT, GET_MODE (index_rtx), + index_rtx, scale_rtx), + base_rtx); + + if (GET_CODE (offset_rtx) != CONST_INT + || INTVAL (offset_rtx) != 0) + ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx), + ret_rtx, offset_rtx); + } + else + { + ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx), + index_rtx, base_rtx); + + if (GET_CODE (offset_rtx) != CONST_INT + || INTVAL (offset_rtx) != 0) + ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx), + ret_rtx, offset_rtx); + } + } + else + { + if (scale != 1) + { + ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx), + index_rtx, scale_rtx); + + if (GET_CODE (offset_rtx) != CONST_INT + || INTVAL (offset_rtx) != 0) + ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx), + ret_rtx, offset_rtx); + } + else + { + if (GET_CODE (offset_rtx) == CONST_INT + && INTVAL (offset_rtx) == 0) + ret_rtx = index_rtx; + else + ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx), + index_rtx, offset_rtx); + } + } + } + else + { + if (base_rtx) + { + if (GET_CODE (offset_rtx) == CONST_INT + && INTVAL (offset_rtx) == 0) + ret_rtx = base_rtx; + else + ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx, + offset_rtx); + } + else if (was_only_offset) + ret_rtx = offset_rtx; + else + { + obfree (storage); + return; + } + } + + XEXP (mem_rtx, 0) = ret_rtx; + RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx; + return; + } + else + { + obfree (storage); + return; + } +} +#endif /* NOTYET */ + +/* Return 1 if the first insn to set cc before INSN also sets the register + REG_RTX; otherwise return 0. */ +int +last_to_set_cc (reg_rtx, insn) + rtx reg_rtx, insn; +{ + rtx prev_insn = PREV_INSN (insn); + + while (prev_insn) + { + if (GET_CODE (prev_insn) == NOTE) + ; + + else if (GET_CODE (prev_insn) == INSN) + { + if (GET_CODE (PATTERN (prev_insn)) != SET) + return (0); + + if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx)) + { + if (sets_condition_code (SET_SRC (PATTERN (prev_insn)))) + return (1); + + return (0); + } + + else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn)))) + return (0); + } + + else + return (0); + + prev_insn = PREV_INSN (prev_insn); + } + + return (0); +} + +int +doesnt_set_condition_code (pat) + rtx pat; +{ + switch (GET_CODE (pat)) + { + case MEM: + case REG: + return 1; + + default: + return 0; + + } +} + +int +sets_condition_code (pat) + rtx pat; +{ + switch (GET_CODE (pat)) + { + case PLUS: + case MINUS: + case AND: + case IOR: + case XOR: + case NOT: + case NEG: + case MULT: + case DIV: + case MOD: + case UDIV: + case UMOD: + return 1; + + default: + return (0); + } +} + +int +str_immediate_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0) + return 1; + + return 0; +} + +int +is_fp_insn (insn) + rtx insn; +{ + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET + && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)) + return 1; + + return 0; +} + +/* Return 1 if the mode of the SET_DEST of insn is floating point + and it is not an fld or a move from memory to memory. + Otherwise return 0 */ + +int +is_fp_dest (insn) + rtx insn; +{ + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET + && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode) + && GET_CODE (SET_DEST (PATTERN (insn))) == REG + && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG + && GET_CODE (SET_SRC (PATTERN (insn))) != MEM) + return 1; + + return 0; +} + +/* Return 1 if the mode of the SET_DEST of INSN is floating point and is + memory and the source is a register. */ + +int +is_fp_store (insn) + rtx insn; +{ + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET + && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode + || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode) + && GET_CODE (SET_DEST (PATTERN (insn))) == MEM + && GET_CODE (SET_SRC (PATTERN (insn))) == REG) + return 1; + + return 0; +} + +/* Return 1 if DEP_INSN sets a register which INSN uses as a base + or index to reference memory. + otherwise return 0 */ + +int +agi_dependent (insn, dep_insn) + rtx insn, dep_insn; +{ + int push = 0, push_dep = 0; + if (GET_CODE (dep_insn) == INSN + && GET_CODE (PATTERN (dep_insn)) == SET + && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG + && reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn)) + return 1; + + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET + && GET_CODE (SET_DEST (PATTERN (insn))) == MEM + && push_operand (SET_DEST (PATTERN (insn)), + GET_MODE (SET_DEST (PATTERN (insn))))) + push = 1; + + if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET + && GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM + && push_operand (SET_DEST (PATTERN (dep_insn)), + GET_MODE (SET_DEST (PATTERN (dep_insn))))) + push_dep = 1; + + /* CPUs contain special hardware to allow two pushes. */ + if (push && push_dep) + return 0; + + /* Push operation implicitly change stack pointer causing AGI stalls. */ + if (push_dep && reg_mentioned_in_mem (stack_pointer_rtx, insn)) + return 1; + + /* Push also implicitly read stack pointer. */ + if (push && modified_in_p (stack_pointer_rtx, dep_insn)) + return 1; + + return 0; +} + +/* Return 1 if reg is used in rtl as a base or index for a memory ref + otherwise return 0. */ + +int +reg_mentioned_in_mem (reg, rtl) + rtx reg, rtl; +{ + register char *fmt; + register int i, j; + register enum rtx_code code; + + if (rtl == NULL) + return 0; + + code = GET_CODE (rtl); + + switch (code) + { + case HIGH: + case CONST_INT: + case CONST: + case CONST_DOUBLE: + case SYMBOL_REF: + case LABEL_REF: + case PC: + case CC0: + case SUBREG: + return 0; + default: + break; + } + + if (code == MEM && reg_mentioned_p (reg, rtl)) + return 1; + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + for (j = XVECLEN (rtl, i) - 1; j >= 0; j--) + if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j))) + return 1; + } + + else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i))) + return 1; + } + + return 0; +} + +/* Output the appropriate insns for doing strlen if not just doing repnz; scasb + + operands[0] = result, initialized with the startaddress + operands[1] = alignment of the address. + operands[2] = scratch register, initialized with the startaddress when + not aligned, otherwise undefined + + This is just the body. It needs the initialisations mentioned above and + some address computing at the end. These things are done in i386.md. */ + +char * +output_strlen_unroll (operands) + rtx operands[]; +{ + rtx xops[18]; + + xops[0] = operands[0]; /* Result */ + /* operands[1]; * Alignment */ + xops[1] = operands[2]; /* Scratch */ + xops[2] = GEN_INT (0); + xops[3] = GEN_INT (2); + xops[4] = GEN_INT (3); + xops[5] = GEN_INT (4); + /* xops[6] = gen_label_rtx (); * label when aligned to 3-byte */ + /* xops[7] = gen_label_rtx (); * label when aligned to 2-byte */ + xops[8] = gen_label_rtx (); /* label of main loop */ + + if (TARGET_USE_Q_REG && QI_REG_P (xops[1])) + xops[9] = gen_label_rtx (); /* pentium optimisation */ + + xops[10] = gen_label_rtx (); /* end label 2 */ + xops[11] = gen_label_rtx (); /* end label 1 */ + xops[12] = gen_label_rtx (); /* end label */ + /* xops[13] * Temporary used */ + xops[14] = GEN_INT (0xff); + xops[15] = GEN_INT (0xff00); + xops[16] = GEN_INT (0xff0000); + xops[17] = GEN_INT (0xff000000); + + /* Loop to check 1..3 bytes for null to get an aligned pointer. */ + + /* Is there a known alignment and is it less than 4? */ + if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4) + { + /* Is there a known alignment and is it not 2? */ + if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2) + { + xops[6] = gen_label_rtx (); /* Label when aligned to 3-byte */ + xops[7] = gen_label_rtx (); /* Label when aligned to 2-byte */ + + /* Leave just the 3 lower bits. + If this is a q-register, then the high part is used later + therefore use andl rather than andb. */ + output_asm_insn (AS2 (and%L1,%4,%1), xops); + + /* Is aligned to 4-byte address when zero */ + output_asm_insn (AS1 (je,%l8), xops); + + /* Side-effect even Parity when %eax == 3 */ + output_asm_insn (AS1 (jp,%6), xops); + + /* Is it aligned to 2 bytes ? */ + if (QI_REG_P (xops[1])) + output_asm_insn (AS2 (cmp%L1,%3,%1), xops); + else + output_asm_insn (AS2 (cmp%L1,%3,%1), xops); + + output_asm_insn (AS1 (je,%7), xops); + } + else + { + /* Since the alignment is 2, we have to check 2 or 0 bytes; + check if is aligned to 4 - byte. */ + output_asm_insn (AS2 (and%L1,%3,%1), xops); + + /* Is aligned to 4-byte address when zero */ + output_asm_insn (AS1 (je,%l8), xops); + } + + xops[13] = gen_rtx_MEM (QImode, xops[0]); + + /* Now compare the bytes; compare with the high part of a q-reg + gives shorter code. */ + if (QI_REG_P (xops[1])) + { + /* Compare the first n unaligned byte on a byte per byte basis. */ + output_asm_insn (AS2 (cmp%B1,%h1,%13), xops); + + /* When zero we reached the end. */ + output_asm_insn (AS1 (je,%l12), xops); + + /* Increment the address. */ + output_asm_insn (AS1 (inc%L0,%0), xops); + + /* Not needed with an alignment of 2 */ + if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2) + { + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[7])); + output_asm_insn (AS2 (cmp%B1,%h1,%13), xops); + output_asm_insn (AS1 (je,%l12), xops); + output_asm_insn (AS1 (inc%L0,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[6])); + } + + output_asm_insn (AS2 (cmp%B1,%h1,%13), xops); + } + else + { + output_asm_insn (AS2 (cmp%B13,%2,%13), xops); + output_asm_insn (AS1 (je,%l12), xops); + output_asm_insn (AS1 (inc%L0,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[7])); + output_asm_insn (AS2 (cmp%B13,%2,%13), xops); + output_asm_insn (AS1 (je,%l12), xops); + output_asm_insn (AS1 (inc%L0,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[6])); + output_asm_insn (AS2 (cmp%B13,%2,%13), xops); + } + + output_asm_insn (AS1 (je,%l12), xops); + output_asm_insn (AS1 (inc%L0,%0), xops); + } + + /* Generate loop to check 4 bytes at a time. It is not a good idea to + align this loop. It gives only huge programs, but does not help to + speed up. */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8])); + + xops[13] = gen_rtx_MEM (SImode, xops[0]); + output_asm_insn (AS2 (mov%L1,%13,%1), xops); + + if (QI_REG_P (xops[1])) + { + /* On i586 it is faster to combine the hi- and lo- part as + a kind of lookahead. If anding both yields zero, then one + of both *could* be zero, otherwise none of both is zero; + this saves one instruction, on i486 this is slower + tested with P-90, i486DX2-66, AMD486DX2-66 */ + if (TARGET_PENTIUM) + { + output_asm_insn (AS2 (test%B1,%h1,%b1), xops); + output_asm_insn (AS1 (jne,%l9), xops); + } + + /* Check first byte. */ + output_asm_insn (AS2 (test%B1,%b1,%b1), xops); + output_asm_insn (AS1 (je,%l12), xops); + + /* Check second byte. */ + output_asm_insn (AS2 (test%B1,%h1,%h1), xops); + output_asm_insn (AS1 (je,%l11), xops); + + if (TARGET_PENTIUM) + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (xops[9])); + } + + else + { + /* Check first byte. */ + output_asm_insn (AS2 (test%L1,%14,%1), xops); + output_asm_insn (AS1 (je,%l12), xops); + + /* Check second byte. */ + output_asm_insn (AS2 (test%L1,%15,%1), xops); + output_asm_insn (AS1 (je,%l11), xops); + } + + /* Check third byte. */ + output_asm_insn (AS2 (test%L1,%16,%1), xops); + output_asm_insn (AS1 (je,%l10), xops); + + /* Check fourth byte and increment address. */ + output_asm_insn (AS2 (add%L0,%5,%0), xops); + output_asm_insn (AS2 (test%L1,%17,%1), xops); + output_asm_insn (AS1 (jne,%l8), xops); + + /* Now generate fixups when the compare stops within a 4-byte word. */ + output_asm_insn (AS2 (sub%L0,%4,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10])); + output_asm_insn (AS1 (inc%L0,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11])); + output_asm_insn (AS1 (inc%L0,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12])); + + return ""; +} + +char * +output_fp_conditional_move (which_alternative, operands) + int which_alternative; + rtx operands[]; +{ + enum rtx_code code = GET_CODE (operands[1]); + + /* This should never happen. */ + if (!(cc_prev_status.flags & CC_IN_80387) + && (code == GT || code == LE || code == GE || code == LT)) + abort (); + + switch (which_alternative) + { + case 0: + /* r <- cond ? arg : r */ + output_asm_insn (AS2 (fcmov%F1,%2,%0), operands); + break; + + case 1: + /* r <- cond ? r : arg */ + output_asm_insn (AS2 (fcmov%f1,%3,%0), operands); + break; + + default: + abort (); + } + + return ""; +} + +char * +output_int_conditional_move (which_alternative, operands) + int which_alternative; + rtx operands[]; +{ + enum rtx_code code = GET_CODE (operands[1]); + + /* This is very tricky. We have to do it right. For a code segement + like: + + int foo, bar; + .... + foo = foo - x; + if (foo >= 0) + bar = y; + + final_scan_insn () may delete the insn which sets CC. We have to + tell final_scan_insn () if it should be reinserted. When CODE is + GT or LE, we have to check the CC_NO_OVERFLOW bit and return + NULL_PTR to tell final to reinsert the test insn because the + conditional move cannot be handled properly without it. */ + if ((code == GT || code == LE) + && (cc_prev_status.flags & CC_NO_OVERFLOW)) + return NULL_PTR; + + switch (which_alternative) + { + case 0: + /* r <- cond ? arg : r */ + output_asm_insn (AS2 (cmov%C1,%2,%0), operands); + break; + + case 1: + /* r <- cond ? r : arg */ + output_asm_insn (AS2 (cmov%c1,%3,%0), operands); + break; + + default: + abort (); + } + + return ""; +} + +int +x86_adjust_cost (insn, link, dep_insn, cost) + rtx insn, link, dep_insn; + int cost; +{ + rtx next_inst; + + if (GET_CODE (dep_insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) + return 0; + + if (GET_CODE (dep_insn) == INSN + && GET_CODE (PATTERN (dep_insn)) == SET + && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)), + SET_SRC (PATTERN (insn)))) + return 0; /* ??? */ + + + switch (ix86_cpu) + { + case PROCESSOR_PENTIUM: + if (cost != 0 && is_fp_insn (insn) && is_fp_insn (dep_insn) + && !is_fp_dest (dep_insn)) + return 0; + + if (agi_dependent (insn, dep_insn)) + return cost ? cost + 1 : 2; + + if (GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == SET + && SET_DEST (PATTERN (insn)) == cc0_rtx + && (next_inst = next_nonnote_insn (insn)) + && GET_CODE (next_inst) == JUMP_INSN) + /* compare probably paired with jump */ + return 0; + + /* Stores stalls one cycle longer than other insns. */ + if (is_fp_insn (insn) && cost && is_fp_store (dep_insn)) + cost++; + break; + case PROCESSOR_K6: + default: + if (!is_fp_dest (dep_insn)) + { + if(!agi_dependent (insn, dep_insn)) + return 0; + if (TARGET_486) + return 2; + } + else + if (is_fp_store (insn) && is_fp_insn (dep_insn) + && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn)) + && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))) + && (GET_CODE (NEXT_INSN (insn)) == INSN) + && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN) + && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE) + && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) + == NOTE_INSN_LOOP_END)) + return 3; + break; + } + + return cost; +} + +/* Output assembly code for a left shift. + + Always use "sal" when shifting a memory operand or for a non constant + shift count. + + When optimizing for size, we know that src == dest, and we should always + use "sal". If src != dest, then copy src to dest and use "sal". + + Pentium and PPro (speed): + + When src == dest, use "add" for a shift counts of one, else use + "sal". If we modeled Pentium AGI stalls and U/V pipelining better we + would want to generate lea for some shifts on the Pentium. + + When src != dest, use "lea" for small shift counts. Otherwise, + copy src to dest and use the normal shifting code. Exception for + TARGET_DOUBLE_WITH_ADD. */ + +char * +output_ashl (insn, operands) + rtx insn, *operands; +{ + /* Handle case where srcreg != dstreg. */ + if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) + { + if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1) + switch (GET_MODE (operands[0])) + { + case SImode: + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + return AS2 (add%L0,%1,%0); + case HImode: + output_asm_insn (AS2 (mov%L0,%k1,%k0), operands); + if (i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS2 (add%L0,%k1,%k0); + } + return AS2 (add%W0,%k1,%k0); + case QImode: + output_asm_insn (AS2 (mov%B0,%1,%0), operands); + return AS2 (add%B0,%1,%0); + default: + abort (); + } + else + { + CC_STATUS_INIT; + + /* This should be extremely rare (impossible?). We can not encode a + shift of the stack pointer using an lea instruction. So copy the + stack pointer into the destination register and use an lea. */ + if (operands[1] == stack_pointer_rtx) + { + output_asm_insn (AS2 (mov%L0,%k1,%k0), operands); + operands[1] = operands[0]; + } + + /* For shifts up to and including 3 bits, use lea. */ + operands[1] = gen_rtx_MULT (SImode, + gen_rtx_REG (SImode, REGNO (operands[1])), + GEN_INT (1 << INTVAL (operands[2]))); + return AS2 (lea%L0,%a1,%k0); + } + } + + /* Source and destination match. */ + + /* Handle variable shift. */ + if (REG_P (operands[2])) + switch (GET_MODE (operands[0])) + { + case SImode: + return AS2 (sal%L0,%b2,%0); + case HImode: + if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS2 (sal%L0,%b2,%k0); + } + else + return AS2 (sal%W0,%b2,%0); + case QImode: + return AS2 (sal%B0,%b2,%0); + default: + abort (); + } + + /* Always perform shift by 1 using an add instruction. */ + if (REG_P (operands[0]) && operands[2] == const1_rtx) + switch (GET_MODE (operands[0])) + { + case SImode: + return AS2 (add%L0,%0,%0); + case HImode: + if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS2 (add%L0,%k0,%k0); + } + else + return AS2 (add%W0,%0,%0); + case QImode: + return AS2 (add%B0,%0,%0); + default: + abort (); + } + +#if 0 + /* ??? Currently disabled. Because our model of Pentium is far from being + exact, this change will need some benchmarking. */ + /* Shift reg by 2 or 3 use an lea instruction for Pentium if this is + insn is expected to issue into the V pipe (the insn's mode will be + TImode for a U pipe, and !TImode for a V pipe instruction). */ + if (! optimize_size + && REG_P (operands[0]) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) <= 3 + && (int)ix86_cpu == (int)PROCESSOR_PENTIUM + && GET_MODE (insn) != TImode) + { + CC_STATUS_INIT; + operands[1] = gen_rtx_MULT (SImode, gen_rtx_REG (SImode, REGNO (operands[1])), + GEN_INT (1 << INTVAL (operands[2]))); + return AS2 (lea%L0,%a1,%0); + } +#endif + + /* Otherwise use a shift instruction. */ + switch (GET_MODE (operands[0])) + { + case SImode: + return AS2 (sal%L0,%2,%0); + case HImode: + if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS2 (sal%L0,%2,%k0); + } + else + return AS2 (sal%W0,%2,%0); + case QImode: + return AS2 (sal%B0,%2,%0); + default: + abort (); + } +} + +/* Given the memory address ADDR, calculate the length of the address or + the length of just the displacement (controlled by DISP_LENGTH). + + The length returned does not include the one-byte modrm, opcode, + or prefix. */ + +int +memory_address_info (addr, disp_length) + rtx addr; + int disp_length; +{ + rtx base, index, disp, scale; + rtx op0, op1; + int len; + + if (GET_CODE (addr) == PRE_DEC + || GET_CODE (addr) == POST_INC) + return 0; + + /* Register Indirect. */ + if (register_operand (addr, Pmode)) + { + /* Special cases: ebp and esp need the two-byte modrm form. + + We change [ESI] to [ESI+0] on the K6 when not optimizing + for size. */ + if (addr == stack_pointer_rtx + || addr == arg_pointer_rtx + || addr == frame_pointer_rtx + || (REGNO_REG_CLASS (REGNO (addr)) == SIREG + && ix86_cpu == PROCESSOR_K6 && !optimize_size)) + return 1; + else + return 0; + } + + /* Direct Addressing. */ + if (CONSTANT_P (addr)) + return 4; + + index = base = disp = scale = NULL_RTX; + op0 = XEXP (addr, 0); + op1 = XEXP (addr, 1); + + if (GET_CODE (addr) == PLUS) + { + if (register_operand (op0, Pmode)) + { + if (register_operand (op1, Pmode)) + index = op0, base = op1; + else + base = op0, disp = op1; + } + else if (GET_CODE (op0) == MULT) + { + index = XEXP (op0, 0); + scale = XEXP (op0, 1); + if (register_operand (op1, Pmode)) + base = op1; + else + disp = op1; + } + else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) + { + index = XEXP (XEXP (op0, 0), 0); + scale = XEXP (XEXP (op0, 0), 1); + base = XEXP (op0, 1); + disp = op1; + } + else if (GET_CODE (op0) == PLUS) + { + index = XEXP (op0, 0); + base = XEXP (op0, 1); + disp = op1; + } + else + abort (); + } + else if (GET_CODE (addr) == MULT + /* We're called for lea too, which implements ashift on occasion. */ + || GET_CODE (addr) == ASHIFT) + { + index = XEXP (addr, 0); + scale = XEXP (addr, 1); + } + else + abort (); + + /* Allow arg pointer and stack pointer as index if there is not scaling */ + if (base && index && !scale + && (index == stack_pointer_rtx + || index == arg_pointer_rtx + || index == frame_pointer_rtx)) + { + rtx tmp = base; + base = index; + index = tmp; + } + + /* Special case: ebp cannot be encoded as a base without a displacement. */ + if (base == frame_pointer_rtx && !disp) + disp = const0_rtx; + + /* Scaling can not be encoded without base or displacement. + Except for scale == 1 where we can encode reg + reg instead of reg * 2. */ + if (!base && index + && (!scale || GET_CODE (scale) != CONST_INT || (INTVAL (scale) != 1))) + disp = const0_rtx; + + /* Find the length of the displacement constant. */ + len = 0; + if (disp) + { + if (GET_CODE (disp) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K')) + len = 1; + else + len = 4; + } + + /* An index requires the two-byte modrm form. Not important + if we are computing just length of the displacement. */ + if (index && ! disp_length) + len += 1; + + return len; +} diff --git a/gnu/egcs/gcc/config/i386/i386.h b/gnu/egcs/gcc/config/i386/i386.h new file mode 100644 index 00000000000..5e27fd80034 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386.h @@ -0,0 +1,2810 @@ +/* Definitions of target machine for GNU compiler for Intel X86 + (386, 486, Pentium). + Copyright (C) 1988, 92, 94, 95, 96, 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. */ + +/* The purpose of this file is to define the characteristics of the i386, + independent of assembler syntax or operating system. + + Three other files build on this one to describe a specific assembler syntax: + bsd386.h, att386.h, and sun386.h. + + The actual tm.h file for a particular system should include + this file, and then the file for the appropriate assembler syntax. + + Many macros that specify assembler syntax are omitted entirely from + this file because they really belong in the files for particular + assemblers. These include AS1, AS2, AS3, RP, IP, LPREFIX, L_SIZE, + PUT_OP_SIZE, USE_STAR, ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, + PRINT_B_I_S, and many that start with ASM_ or end in ASM_OP. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define I386 1 + +/* Stubs for half-pic support if not OSF/1 reference platform. */ + +#ifndef HALF_PIC_P +#define HALF_PIC_P() 0 +#define HALF_PIC_NUMBER_PTRS 0 +#define HALF_PIC_NUMBER_REFS 0 +#define HALF_PIC_ENCODE(DECL) +#define HALF_PIC_DECLARE(NAME) +#define HALF_PIC_INIT() error ("half-pic init called on systems that don't support it.") +#define HALF_PIC_ADDRESS_P(X) 0 +#define HALF_PIC_PTR(X) X +#define HALF_PIC_FINISH(STREAM) +#endif + +/* Define the specific costs for a given cpu */ + +struct processor_costs { + int add; /* cost of an add instruction */ + int lea; /* cost of a lea instruction */ + int shift_var; /* variable shift costs */ + int shift_const; /* constant shift costs */ + int mult_init; /* cost of starting a multiply */ + int mult_bit; /* cost of multiply per each bit set */ + int divide; /* cost of a divide/mod */ +}; + +extern struct processor_costs *ix86_cost; + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int target_flags; + +/* Macros used in the machine description to test the flags. */ + +/* configure can arrange to make this 2, to force a 486. */ +#ifndef TARGET_CPU_DEFAULT +#define TARGET_CPU_DEFAULT 0 +#endif + +/* Masks for the -m switches */ +#define MASK_80387 000000000001 /* Hardware floating point */ +#define MASK_NOTUSED1 000000000002 /* bit not currently used */ +#define MASK_NOTUSED2 000000000004 /* bit not currently used */ +#define MASK_RTD 000000000010 /* Use ret that pops args */ +#define MASK_ALIGN_DOUBLE 000000000020 /* align doubles to 2 word boundary */ +#define MASK_SVR3_SHLIB 000000000040 /* Uninit locals into bss */ +#define MASK_IEEE_FP 000000000100 /* IEEE fp comparisons */ +#define MASK_FLOAT_RETURNS 000000000200 /* Return float in st(0) */ +#define MASK_NO_FANCY_MATH_387 000000000400 /* Disable sin, cos, sqrt */ +#define MASK_OMIT_LEAF_FRAME_POINTER 0x00000800 /* omit leaf frame pointers */ + /* Temporary codegen switches */ +#define MASK_DEBUG_ADDR 000001000000 /* Debug GO_IF_LEGITIMATE_ADDRESS */ +#define MASK_NO_WIDE_MULTIPLY 000002000000 /* Disable 32x32->64 multiplies */ +#define MASK_NO_MOVE 000004000000 /* Don't generate mem->mem */ +#define MASK_NO_PSEUDO 000010000000 /* Move op's args -> pseudos */ +#define MASK_DEBUG_ARG 000020000000 /* Debug function_arg */ +#define MASK_SCHEDULE_PROLOGUE 000040000000 /* Emit prologue as rtl */ +#define MASK_STACK_PROBE 000100000000 /* Enable stack probing */ + +/* Use the floating point instructions */ +#define TARGET_80387 (target_flags & MASK_80387) + +/* Compile using ret insn that pops args. + This will not work unless you use prototypes at least + for all functions that can take varying numbers of args. */ +#define TARGET_RTD (target_flags & MASK_RTD) + +/* Align doubles to a two word boundary. This breaks compatibility with + the published ABI's for structures containing doubles, but produces + faster code on the pentium. */ +#define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE) + +/* Put uninitialized locals into bss, not data. + Meaningful only on svr3. */ +#define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB) + +/* Use IEEE floating point comparisons. These handle correctly the cases + where the result of a comparison is unordered. Normally SIGFPE is + generated in such cases, in which case this isn't needed. */ +#define TARGET_IEEE_FP (target_flags & MASK_IEEE_FP) + +/* Functions that return a floating point value may return that value + in the 387 FPU or in 386 integer registers. If set, this flag causes + the 387 to be used, which is compatible with most calling conventions. */ +#define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS) + +/* Disable generation of FP sin, cos and sqrt operations for 387. + This is because FreeBSD lacks these in the math-emulator-code */ +#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387) + +/* Don't create frame pointers for leaf functions */ +#define TARGET_OMIT_LEAF_FRAME_POINTER (target_flags & MASK_OMIT_LEAF_FRAME_POINTER) + +/* Temporary switches for tuning code generation */ + +/* Disable 32x32->64 bit multiplies that are used for long long multiplies + and division by constants, but sometimes cause reload problems. */ +#define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY) +#define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY) + +/* Emit/Don't emit prologue as rtl */ +#define TARGET_SCHEDULE_PROLOGUE (target_flags & MASK_SCHEDULE_PROLOGUE) + +/* Debug GO_IF_LEGITIMATE_ADDRESS */ +#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR) + +/* Debug FUNCTION_ARG macros */ +#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG) + +/* Hack macros for tuning code generation */ +#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */ +#define TARGET_PSEUDO ((target_flags & MASK_NO_PSEUDO) == 0) /* Move op's args into pseudos */ + +#define TARGET_386 (ix86_cpu == PROCESSOR_I386) +#define TARGET_486 (ix86_cpu == PROCESSOR_I486) +#define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM) +#define TARGET_PENTIUMPRO (ix86_cpu == PROCESSOR_PENTIUMPRO) +#define TARGET_K6 (ix86_cpu == PROCESSOR_K6) + +#define CPUMASK (1 << ix86_cpu) +extern const int x86_use_leave, x86_push_memory, x86_zero_extend_with_and; +extern const int x86_use_bit_test, x86_cmove, x86_deep_branch; +extern const int x86_unroll_strlen, x86_use_q_reg, x86_use_any_reg; +extern const int x86_double_with_add; + +#define TARGET_USE_LEAVE (x86_use_leave & CPUMASK) +#define TARGET_PUSH_MEMORY (x86_push_memory & CPUMASK) +#define TARGET_ZERO_EXTEND_WITH_AND (x86_zero_extend_with_and & CPUMASK) +#define TARGET_USE_BIT_TEST (x86_use_bit_test & CPUMASK) +#define TARGET_UNROLL_STRLEN (x86_unroll_strlen & CPUMASK) +#define TARGET_USE_Q_REG (x86_use_q_reg & CPUMASK) +#define TARGET_USE_ANY_REG (x86_use_any_reg & CPUMASK) +#define TARGET_CMOVE (x86_cmove & (1 << ix86_arch)) +#define TARGET_DEEP_BRANCH_PREDICTION (x86_deep_branch & CPUMASK) +#define TARGET_DOUBLE_WITH_ADD (x86_double_with_add & CPUMASK) + +#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE) + +#define TARGET_SWITCHES \ +{ { "80387", MASK_80387, "Use hardware fp" }, \ + { "no-80387", -MASK_80387, "Do not use hardware fp" },\ + { "hard-float", MASK_80387, "Use hardware fp" }, \ + { "soft-float", -MASK_80387, "Do not use hardware fp" },\ + { "no-soft-float", MASK_80387, "Use hardware fp" }, \ + { "386", 0, "Same as -mcpu=i386" }, \ + { "486", 0, "Same as -mcpu=i486" }, \ + { "pentium", 0, "Same as -mcpu=pentium" }, \ + { "pentiumpro", 0, "Same as -mcpu=pentiumpro" }, \ + { "rtd", MASK_RTD, "Alternate calling convention" },\ + { "no-rtd", -MASK_RTD, "Use normal calling convention" },\ + { "align-double", MASK_ALIGN_DOUBLE, "Align some doubles on dword boundary" },\ + { "no-align-double", -MASK_ALIGN_DOUBLE, "Align doubles on word boundary" }, \ + { "svr3-shlib", MASK_SVR3_SHLIB, "Uninitialized locals in .bss" }, \ + { "no-svr3-shlib", -MASK_SVR3_SHLIB, "Uninitialized locals in .data" }, \ + { "ieee-fp", MASK_IEEE_FP, "Use IEEE math for fp comparisons" }, \ + { "no-ieee-fp", -MASK_IEEE_FP, "Do not use IEEE math for fp comparisons" }, \ + { "fp-ret-in-387", MASK_FLOAT_RETURNS, "Return values of functions in FPU registers" }, \ + { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , "Do not return values of functions in FPU registers"}, \ + { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, "Do not generate sin, cos, sqrt for 387" }, \ + { "fancy-math-387", -MASK_NO_FANCY_MATH_387, "Generate sin, cos, sqrt for FPU"}, \ + { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, "Omit the frame pointer in leaf functions" }, \ + { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \ + { "no-wide-multiply", MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits constrained to 32 bits" }, \ + { "wide-multiply", -MASK_NO_WIDE_MULTIPLY, "multiplies of 32 bits are 64 bits" }, \ + { "schedule-prologue", MASK_SCHEDULE_PROLOGUE, "Schedule function prologues" }, \ + { "no-schedule-prologue", -MASK_SCHEDULE_PROLOGUE, "" }, \ + { "debug-addr", MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \ + { "no-debug-addr", -MASK_DEBUG_ADDR, 0 /* intentionally undoc */ }, \ + { "move", -MASK_NO_MOVE, "Generate mem-mem moves" }, \ + { "no-move", MASK_NO_MOVE, "Don't generate mem-mem moves" }, \ + { "debug-arg", MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \ + { "no-debug-arg", -MASK_DEBUG_ARG, 0 /* intentionally undoc */ }, \ + { "stack-arg-probe", MASK_STACK_PROBE, "Enable stack probing" }, \ + { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \ + { "windows", 0, 0 /* intentionally undoc */ }, \ + { "dll", 0, 0 /* intentionally undoc */ }, \ + SUBTARGET_SWITCHES \ + { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT, 0 }} + +/* Which processor to schedule for. The cpu attribute defines a list that + mirrors this list, so changes to i386.md must be made at the same time. */ + +enum processor_type + {PROCESSOR_I386, /* 80386 */ + PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */ + PROCESSOR_PENTIUM, + PROCESSOR_PENTIUMPRO, + PROCESSOR_K6}; + +#define PROCESSOR_I386_STRING "i386" +#define PROCESSOR_I486_STRING "i486" +#define PROCESSOR_I586_STRING "i586" +#define PROCESSOR_PENTIUM_STRING "pentium" +#define PROCESSOR_I686_STRING "i686" +#define PROCESSOR_PENTIUMPRO_STRING "pentiumpro" +#define PROCESSOR_K6_STRING "k6" + +extern enum processor_type ix86_cpu; + +extern int ix86_arch; + +/* Define the default processor. This is overridden by other tm.h files. */ +#define PROCESSOR_DEFAULT (enum processor_type) TARGET_CPU_DEFAULT +#define PROCESSOR_DEFAULT_STRING \ + (PROCESSOR_DEFAULT == PROCESSOR_I486 ? PROCESSOR_I486_STRING \ + : PROCESSOR_DEFAULT == PROCESSOR_PENTIUM ? PROCESSOR_PENTIUM_STRING \ + : PROCESSOR_DEFAULT == PROCESSOR_PENTIUMPRO ? PROCESSOR_PENTIUMPRO_STRING \ + : PROCESSOR_DEFAULT == PROCESSOR_K6 ? PROCESSOR_K6_STRING \ + : PROCESSOR_I386_STRING) + +/* 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 \ +{ { "cpu=", &ix86_cpu_string, "Schedule code for given CPU"}, \ + { "arch=", &ix86_arch_string, "Generate code for given CPU"}, \ + { "reg-alloc=", &i386_reg_alloc_order, "Control allocation order of integer registers" }, \ + { "regparm=", &i386_regparm_string, "Number of registers used to pass integer arguments" }, \ + { "align-loops=", &i386_align_loops_string, "Loop code aligned to this power of 2" }, \ + { "align-jumps=", &i386_align_jumps_string, "Jump targets are aligned to this power of 2" }, \ + { "align-functions=", &i386_align_funcs_string, "Function starts are aligned to this power of 2" }, \ + { "preferred-stack-boundary=", &i386_preferred_stack_boundary_string, "Attempt to keep stack aligned to this power of 2" }, \ + { "branch-cost=", &i386_branch_cost_string, "Branches are this expensive (1-5, arbitrary units)" }, \ + 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 () + +/* These are meant to be redefined in the host dependent files */ +#define SUBTARGET_SWITCHES +#define SUBTARGET_OPTIONS + +/* Define this to change the optimizations performed by default. */ +#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE) + +/* Specs for the compiler proper */ + +#ifndef CC1_CPU_SPEC +#define CC1_CPU_SPEC "\ +%{!mcpu*: \ +%{m386:-mcpu=i386 -march=i386} \ +%{m486:-mcpu=i486 -march=i486} \ +%{mpentium:-mcpu=pentium} \ +%{mpentiumpro:-mcpu=pentiumpro}}" +#endif + +#define CPP_486_SPEC "%{!ansi:-Di486} -D__i486 -D__i486__" +#define CPP_586_SPEC "%{!ansi:-Di586 -Dpentium} \ + -D__i586 -D__i586__ -D__pentium -D__pentium__" +#define CPP_K6_SPEC "%{!ansi:-Di586 -Dk6} \ + -D__i586 -D__i586__ -D__k6 -D__k6__" +#define CPP_686_SPEC "%{!ansi:-Di686 -Dpentiumpro} \ + -D__i686 -D__i686__ -D__pentiumpro -D__pentiumpro__" + +#ifndef CPP_CPU_DEFAULT_SPEC +#if TARGET_CPU_DEFAULT == 1 +#define CPP_CPU_DEFAULT_SPEC "%(cpp_486)" +#endif +#if TARGET_CPU_DEFAULT == 2 +#define CPP_CPU_DEFAULT_SPEC "%(cpp_586)" +#endif +#if TARGET_CPU_DEFAULT == 3 +#define CPP_CPU_DEFAULT_SPEC "%(cpp_686)" +#endif +#if TARGET_CPU_DEFAULT == 4 +#define CPP_CPU_DEFAULT_SPEC "%(cpp_k6)" +#endif +#ifndef CPP_CPU_DEFAULT_SPEC +#define CPP_CPU_DEFAULT_SPEC "" +#endif +#endif /* CPP_CPU_DEFAULT_SPEC */ + +#ifndef CPP_CPU_SPEC +#define CPP_CPU_SPEC "\ +-Acpu(i386) -Amachine(i386) \ +%{!ansi:-Di386} -D__i386 -D__i386__ \ +%{mcpu=i486:%(cpp_486)} %{m486:%(cpp_486)} \ +%{mpentium:%(cpp_586)} %{mcpu=pentium:%(cpp_586)} \ +%{mpentiumpro:%(cpp_686)} %{mcpu=pentiumpro:%(cpp_686)} \ +%{mcpu=k6:%(cpp_k6)} \ +%{!mcpu*:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}" +#endif + +#ifndef CC1_SPEC +#define CC1_SPEC "%(cc1_spec) " +#endif + +/* 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. */ + +#ifndef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS +#endif + +#define EXTRA_SPECS \ + { "cpp_486", CPP_486_SPEC}, \ + { "cpp_586", CPP_586_SPEC}, \ + { "cpp_k6", CPP_K6_SPEC}, \ + { "cpp_686", CPP_686_SPEC}, \ + { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \ + { "cpp_cpu", CPP_CPU_SPEC }, \ + { "cc1_cpu", CC1_CPU_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +/* 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 byte of a word is the lowest numbered. */ +/* That is true on the 80386. */ + +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. */ +/* That is not true on the 80386. */ +#define BYTES_BIG_ENDIAN 0 + +/* Define this if most significant word of a multiword number is the lowest + numbered. */ +/* Not true for 80386 */ +#define WORDS_BIG_ENDIAN 0 + +/* number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a 80386, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which the stack pointer must be aligned. */ +#define STACK_BOUNDARY 32 + +/* Boundary (in *bits*) on which the stack pointer preferrs to be + aligned; the compiler cannot rely on having this alignment. */ +#define PREFERRED_STACK_BOUNDARY i386_preferred_stack_boundary + +/* Allocation boundary (in *bits*) for the code of a function. + For i486, we get better performance by aligning to a cache + line (i.e. 16 byte) boundary. */ +#define FUNCTION_BOUNDARY (1 << (i386_align_funcs + 3)) + +/* Alignment of field after `int : 0' in a structure. */ + +#define EMPTY_FIELD_BOUNDARY 32 + +/* Minimum size in bits of the largest boundary to which any + and all fundamental data types supported by the hardware + might need to be aligned. No data type wants to be aligned + rounder than this. The i386 supports 64-bit floating point + quantities, but these can be aligned on any 32-bit boundary. + The published ABIs say that doubles should be aligned on word + boundaries, but the Pentium gets better performance with them + aligned on 64 bit boundaries. */ +#define BIGGEST_ALIGNMENT (TARGET_ALIGN_DOUBLE ? 64 : 32) + +/* If defined, a C expression to compute the alignment given to a + constant that is being placed in memory. CONSTANT is the constant + and ALIGN is the alignment that the object would ordinarily have. + The value of this macro is used instead of that alignment to align + the object. + + If this macro is not defined, then ALIGN is used. + + The typical use of this macro is to increase alignment for string + constants to be word aligned so that `strcpy' calls that copy + constants can be done inline. */ + +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == REAL_CST \ + ? ((TYPE_MODE (TREE_TYPE (EXP)) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TREE_TYPE (EXP)) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : TREE_CODE (EXP) == STRING_CST \ + ? ((TREE_STRING_LENGTH (EXP) >= 31 && (ALIGN) < 256) \ + ? 256 \ + : (ALIGN)) \ + : (ALIGN)) + +/* If defined, a C expression to compute the alignment for a static + variable. TYPE is the data type, and ALIGN is the alignment that + the object would ordinarily have. The value of this macro is used + instead of that alignment to align the object. + + If this macro is not defined, then ALIGN is used. + + One use of this macro is to increase alignment of medium-size + data to make it all fit in fewer cache lines. Another is to + cause character arrays to be word-aligned so that `strcpy' calls + that copy constants to character arrays can be done inline. */ + +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + ((AGGREGATE_TYPE_P (TYPE) \ + && TYPE_SIZE (TYPE) \ + && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ + && (TREE_INT_CST_LOW (TYPE_SIZE (TYPE)) >= 256 \ + || TREE_INT_CST_HIGH (TYPE_SIZE (TYPE))) && (ALIGN) < 256) \ + ? 256 \ + : TREE_CODE (TYPE) == ARRAY_TYPE \ + ? ((TYPE_MODE (TREE_TYPE (TYPE)) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TREE_TYPE (TYPE)) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : TREE_CODE (TYPE) == COMPLEX_TYPE \ + ? ((TYPE_MODE (TYPE) == DCmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TYPE) == XCmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : ((TREE_CODE (TYPE) == RECORD_TYPE \ + || TREE_CODE (TYPE) == UNION_TYPE \ + || TREE_CODE (TYPE) == QUAL_UNION_TYPE) \ + && TYPE_FIELDS (TYPE)) \ + ? ((DECL_MODE (TYPE_FIELDS (TYPE)) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (DECL_MODE (TYPE_FIELDS (TYPE)) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : TREE_CODE (TYPE) == REAL_TYPE \ + ? ((TYPE_MODE (TYPE) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TYPE) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : (ALIGN)) + +/* If defined, a C expression to compute the alignment for a local + variable. TYPE is the data type, and ALIGN is the alignment that + the object would ordinarily have. The value of this macro is used + instead of that alignment to align the object. + + If this macro is not defined, then ALIGN is used. + + One use of this macro is to increase alignment of medium-size + data to make it all fit in fewer cache lines. */ + +#define LOCAL_ALIGNMENT(TYPE, ALIGN) \ + (TREE_CODE (TYPE) == ARRAY_TYPE \ + ? ((TYPE_MODE (TREE_TYPE (TYPE)) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TREE_TYPE (TYPE)) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : TREE_CODE (TYPE) == COMPLEX_TYPE \ + ? ((TYPE_MODE (TYPE) == DCmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TYPE) == XCmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : ((TREE_CODE (TYPE) == RECORD_TYPE \ + || TREE_CODE (TYPE) == UNION_TYPE \ + || TREE_CODE (TYPE) == QUAL_UNION_TYPE) \ + && TYPE_FIELDS (TYPE)) \ + ? ((DECL_MODE (TYPE_FIELDS (TYPE)) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (DECL_MODE (TYPE_FIELDS (TYPE)) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : TREE_CODE (TYPE) == REAL_TYPE \ + ? ((TYPE_MODE (TYPE) == DFmode && (ALIGN) < 64) \ + ? 64 \ + : (TYPE_MODE (TYPE) == XFmode && (ALIGN) < 128) \ + ? 128 \ + : (ALIGN)) \ + : (ALIGN)) + +/* Set this non-zero if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 0 + +/* If bit field type is int, don't let it cross an int, + and give entire struct the alignment of an int. */ +/* Required on the 386 since it doesn't have bitfield insns. */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Maximum power of 2 that code can be aligned to. */ +#define MAX_CODE_ALIGN 6 /* 64 byte alignment */ + +/* Align loop starts for optimal branching. */ +#define LOOP_ALIGN(LABEL) (i386_align_loops) +#define LOOP_ALIGN_MAX_SKIP (i386_align_loops_string ? 0 : 7) + +/* This is how to align an instruction for optimal branching. + On i486 we'll get better performance by aligning on a + cache line (i.e. 16 byte) boundary. */ +#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps) +#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (i386_align_jumps_string ? 0 : 7) + + +/* Standard register usage. */ + +/* This processor has special stack-like registers. See reg-stack.c + for details. */ + +#define STACK_REGS +#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode) + +/* 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. + + In the 80386 we give the 8 general purpose registers the numbers 0-7. + We number the floating point registers 8-15. + Note that registers 0-7 can be accessed as a short or int, + while only 0-3 may be used with byte `mov' instructions. + + Reg 16 does not correspond to any hardware register, but instead + appears in the RTL as an argument pointer prior to reload, and is + eliminated during reloading in favor of either the stack or frame + pointer. */ + +#define FIRST_PSEUDO_REGISTER 17 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. + On the 80386, the stack pointer is such, as is the arg pointer. */ +#define FIXED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 } + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ + +#define CALL_USED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } + +/* Order in which to allocate registers. Each register must be + listed once, even those in FIXED_REGISTERS. List frame pointer + late and fixed registers last. Note that, in general, we prefer + registers listed in CALL_USED_REGISTERS, keeping the others + available for storage of persistent values. + + Three different versions of REG_ALLOC_ORDER have been tried: + + If the order is edx, ecx, eax, ... it produces a slightly faster compiler, + but slower code on simple functions returning values in eax. + + If the order is eax, ecx, edx, ... it causes reload to abort when compiling + perl 4.036 due to not being able to create a DImode register (to hold a 2 + word union). + + If the order is eax, edx, ecx, ... it produces better code for simple + functions, and a slightly slower compiler. Users complained about the code + generated by allocating edx first, so restore the 'natural' order of things. */ + +#define REG_ALLOC_ORDER \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } + +/* A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + +#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () + +/* Macro to conditionally modify fixed_regs/call_used_regs. */ +#define CONDITIONAL_REGISTER_USAGE \ + { \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + } \ + if (! TARGET_80387 && ! TARGET_FLOAT_RETURNS_IN_80387) \ + { \ + int i; \ + HARD_REG_SET x; \ + COPY_HARD_REG_SET (x, reg_class_contents[(int)FLOAT_REGS]); \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \ + if (TEST_HARD_REG_BIT (x, i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ + } + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. + + Actually there are no two word move instructions for consecutive + registers. And only registers 0-3 may have mov byte instructions + applied to them. + */ + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (FP_REGNO_P (REGNO) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. + On the 80386, the first 4 cpu registers can hold any mode + while the floating point registers may hold only floating point. + Make it clear that the fp regs could not hold a 16-byte float. */ + +/* The casts to int placate a compiler on a microvax, + for cross-compiler testing. */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 4 ? 1 \ + : FP_REGNO_P (REGNO) \ + ? (((int) GET_MODE_CLASS (MODE) == (int) MODE_FLOAT \ + || (int) GET_MODE_CLASS (MODE) == (int) MODE_COMPLEX_FLOAT) \ + && GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\ + : (int) (MODE) != (int) QImode ? 1 \ + : (reload_in_progress | reload_completed) == 1) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ((MODE1) == (MODE2) \ + || ((MODE1) == SImode && (MODE2) == HImode) \ + || ((MODE1) == HImode && (MODE2) == SImode)) + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* on the 386 the pc register is %eip, and is not usable as a general + register. The ordinary mov instructions won't work */ +/* #define PC_REGNUM */ + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM 7 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 6 + +/* First floating point reg */ +#define FIRST_FLOAT_REG 8 + +/* First & last stack-like regs */ +#define FIRST_STACK_REG FIRST_FLOAT_REG +#define LAST_STACK_REG (FIRST_FLOAT_REG + 7) + +/* 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 (TARGET_OMIT_LEAF_FRAME_POINTER && !leaf_function_p ()) + +/* Base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM 16 + +/* Register in which static-chain is passed to a function. */ +#define STATIC_CHAIN_REGNUM 2 + +/* Register to hold the addressing base for position independent + code access to data items. */ +#define PIC_OFFSET_TABLE_REGNUM 3 + +/* Register in which address to store a structure value + arrives in the function. On the 386, the prologue + copies this from the stack to register %eax. */ +#define STRUCT_VALUE_INCOMING 0 + +/* Place in which caller passes the structure value address. + 0 means push the value on the stack like an argument. */ +#define STRUCT_VALUE 0 + +/* A C expression which can inhibit the returning of certain function + values in registers, based on the type of value. A nonzero value + says to return the function value in memory, just as large + structures are always returned. Here TYPE will be a C expression + of type `tree', representing the data type of the value. + + Note that values of mode `BLKmode' must be explicitly handled by + this macro. Also, the option `-fpcc-struct-return' takes effect + regardless of this macro. On most systems, it is possible to + leave the macro undefined; this causes a default definition to be + used, whose value is the constant 1 for `BLKmode' values, and 0 + otherwise. + + Do not use this macro to indicate that structures and unions + should always be returned in memory. You should instead use + `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */ + +#define RETURN_IN_MEMORY(TYPE) \ + ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12) + + +/* 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. + + It might seem that class BREG is unnecessary, since no useful 386 + opcode needs reg %ebx. But some systems pass args to the OS in ebx, + and the "b" register constraint is useful in asms for syscalls. */ + +enum reg_class +{ + NO_REGS, + AREG, DREG, CREG, BREG, + AD_REGS, /* %eax/%edx for DImode */ + Q_REGS, /* %eax %ebx %ecx %edx */ + SIREG, DIREG, + INDEX_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp */ + GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */ + FP_TOP_REG, FP_SECOND_REG, /* %st(0) %st(1) */ + FLOAT_REGS, + ALL_REGS, LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define FLOAT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, FLOAT_REGS)) + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ +{ "NO_REGS", \ + "AREG", "DREG", "CREG", "BREG", \ + "AD_REGS", \ + "Q_REGS", \ + "SIREG", "DIREG", \ + "INDEX_REGS", \ + "GENERAL_REGS", \ + "FP_TOP_REG", "FP_SECOND_REG", \ + "FLOAT_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}, \ + {0x1}, {0x2}, {0x4}, {0x8}, /* AREG, DREG, CREG, BREG */ \ + {0x3}, /* AD_REGS */ \ + {0xf}, /* Q_REGS */ \ + {0x10}, {0x20}, /* SIREG, DIREG */ \ + {0x7f}, /* INDEX_REGS */ \ + {0x100ff}, /* GENERAL_REGS */ \ + {0x0100}, {0x0200}, /* FP_TOP_REG, FP_SECOND_REG */ \ + {0xff00}, /* FLOAT_REGS */ \ + {0x1ffff}} + +/* 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) (regclass_map[REGNO]) + +/* When defined, the compiler allows registers explicitly used in the + rtl to be used as spill registers but prevents the compiler from + extending the lifetime of these registers. */ + +#define SMALL_REGISTER_CLASSES 1 + +#define QI_REG_P(X) \ + (REG_P (X) && REGNO (X) < 4) +#define NON_QI_REG_P(X) \ + (REG_P (X) && REGNO (X) >= 4 && REGNO (X) < FIRST_PSEUDO_REGISTER) + +#define FP_REG_P(X) (REG_P (X) && FP_REGNO_P (REGNO (X))) +#define FP_REGNO_P(n) ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) + +#define STACK_REG_P(xop) (REG_P (xop) && \ + REGNO (xop) >= FIRST_STACK_REG && \ + REGNO (xop) <= LAST_STACK_REG) + +#define NON_STACK_REG_P(xop) (REG_P (xop) && ! STACK_REG_P (xop)) + +#define STACK_TOP_P(xop) (REG_P (xop) && REGNO (xop) == FIRST_STACK_REG) + +/* 1 if register REGNO can magically overlap other regs. + Note that nonzero values work only in very special circumstances. */ + +/* #define OVERLAPPING_REGNO_P(REGNO) FP_REGNO_P (REGNO) */ + +/* The class value for index registers, and the one for base regs. */ + +#define INDEX_REG_CLASS INDEX_REGS +#define BASE_REG_CLASS GENERAL_REGS + +/* Get reg_class from a letter such as appears in the machine description. */ + +#define REG_CLASS_FROM_LETTER(C) \ + ((C) == 'r' ? GENERAL_REGS : \ + (C) == 'q' ? Q_REGS : \ + (C) == 'f' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FLOAT_REGS \ + : NO_REGS) : \ + (C) == 't' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FP_TOP_REG \ + : NO_REGS) : \ + (C) == 'u' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ + ? FP_SECOND_REG \ + : NO_REGS) : \ + (C) == 'a' ? AREG : \ + (C) == 'b' ? BREG : \ + (C) == 'c' ? CREG : \ + (C) == 'd' ? DREG : \ + (C) == 'A' ? AD_REGS : \ + (C) == 'D' ? DIREG : \ + (C) == 'S' ? SIREG : NO_REGS) + +/* The letters I, J, K, L and M in a register constraint string + can be used to stand for particular ranges of immediate operands. + This macro defines what the ranges are. + C is the letter, and VALUE is a constant value. + Return 1 if VALUE is in the range specified by C. + + I is for non-DImode shifts. + J is for DImode shifts. + K and L are for an `andsi' optimization. + M is for shifts that can be executed by the "lea" opcode. + */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 : \ + (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 : \ + (C) == 'K' ? (VALUE) == 0xff : \ + (C) == 'L' ? (VALUE) == 0xffff : \ + (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \ + (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\ + (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 32 : \ + 0) + +/* Similar, but for floating constants, and defining letters G and H. + Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if + TARGET_387 isn't set, because the stack register converter may need to + load 0.0 into the function value register. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? standard_80387_constant_p (VALUE) : 0) + +/* Place additional restrictions on the register class to use when it + is necessary to be able to hold a value of mode MODE in a reload + register for which class CLASS would ordinarily be used. */ + +#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ + ((MODE) == QImode && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS) \ + ? Q_REGS : (CLASS)) + +/* 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 80386 series, we prevent floating constants from being + reloaded into floating registers (since no move-insn can do that) + and we ensure that QImodes aren't reloaded into the esi or edi reg. */ + +/* Put float CONST_DOUBLE in the constant pool instead of fp regs. + QImode must go into class Q_REGS. + Narrow ALL_REGS to GENERAL_REGS. This supports allowing movsf and + movdf to do mem-to-mem moves through integer regs. */ + +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode \ + ? (standard_80387_constant_p (X) \ + ? reg_class_subset_p (CLASS, FLOAT_REGS) ? CLASS : FLOAT_REGS \ + : NO_REGS) \ + : GET_MODE (X) == QImode && ! reg_class_subset_p (CLASS, Q_REGS) ? Q_REGS \ + : ((CLASS) == ALL_REGS \ + && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) ? GENERAL_REGS \ + : (CLASS)) + +/* If we are copying between general and FP registers, we need a memory + location. */ + +#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \ + ((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \ + || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +/* On the 80386, this is the size of MODE in words, + except in the FP regs, where a single reg is always enough. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (FLOAT_CLASS_P (CLASS) ? 1 : \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) + +/* A C expression whose value is nonzero if pseudos that have been + assigned to registers of class CLASS would likely be spilled + because registers of CLASS are needed for spill registers. + + The default value of this macro returns 1 if CLASS has exactly one + register and zero otherwise. On most machines, this default + should be used. Only define this macro to some other expression + if pseudo allocated by `local-alloc.c' end up in memory because + their hard registers were needed for spill registers. If this + macro returns nonzero for those classes, those pseudos will only + be allocated by `global.c', which knows how to reallocate the + pseudo to another register. If there would not be another + register available for reallocation, you should not change the + definition of this macro since the only effect of such a + definition would be to slow down register allocation. */ + +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + (((CLASS) == AREG) \ + || ((CLASS) == DREG) \ + || ((CLASS) == CREG) \ + || ((CLASS) == BREG) \ + || ((CLASS) == AD_REGS) \ + || ((CLASS) == SIREG) \ + || ((CLASS) == DIREG)) + + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +#define STACK_GROWS_DOWNWARD + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +#define FRAME_GROWS_DOWNWARD + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + On 386 pushw decrements by exactly 2 no matter what the position was. + On the 386 there is no pushb; we use pushw instead, and this + has the effect of rounding up to 2. */ + +#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2)) + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) 0 + +/* Value is the number of bytes of arguments automatically + popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. + SIZE is the number of bytes of arguments passed on the stack. + + On the 80386, 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. + + The attribute stdcall is equivalent to RTD on a per module basis. */ + +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE)) + +/* Define how to find the value returned by a function. + VALTYPE is the data type of the value (as a tree). + If the precise function being called is known, FUNC is its FUNCTION_DECL; + otherwise, FUNC is 0. */ +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx_REG (TYPE_MODE (VALTYPE), \ + VALUE_REGNO (TYPE_MODE (VALTYPE))) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +#define LIBCALL_VALUE(MODE) \ + gen_rtx_REG (MODE, VALUE_REGNO (MODE)) + +/* Define the size of the result block used for communication between + untyped_call and untyped_return. The block contains a DImode value + followed by the block used by fnsave and frstor. */ + +#define APPLY_RESULT_SIZE (8+108) + +/* 1 if N is a possible register number for function argument passing. */ +#define FUNCTION_ARG_REGNO_P(N) ((N) >= 0 && (N) < REGPARM_MAX) + +/* 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. */ + +typedef struct i386_args { + int words; /* # words passed so far */ + int nregs; /* # registers available for passing */ + int regno; /* next available register number */ +} CUMULATIVE_ARGS; + +/* 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. */ + +#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \ + (init_cumulative_args (&CUM, FNTYPE, LIBNAME)) + +/* 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) \ + (function_arg_advance (&CUM, MODE, TYPE, NAMED)) + +/* 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). */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + (function_arg (&CUM, MODE, TYPE, NAMED)) + +/* 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) \ + (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) + +/* This macro is invoked just before the start of a function. + It is used here to output code for -fpic that will load the + return address into %ebx. */ + +#undef ASM_OUTPUT_FUNCTION_PREFIX +#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \ + asm_output_function_prefix (FILE, FNNAME) + +/* 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. */ + +#define FUNCTION_PROLOGUE(FILE, SIZE) \ + function_prologue (FILE, SIZE) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *_mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall _mcount\n"); \ + } \ +} + + +/* There are three profiling modes for basic blocks available. + The modes are selected at compile time by using the options + -a or -ax of the gnu compiler. + The variable `profile_block_flag' will be set according to the + selected option. + + profile_block_flag == 0, no option used: + + No profiling done. + + profile_block_flag == 1, -a option used. + + Count frequency of execution of every basic block. + + profile_block_flag == 2, -ax option used. + + Generate code to allow several different profiling modes at run time. + Available modes are: + Produce a trace of all basic blocks. + Count frequency of jump instructions executed. + In every mode it is possible to start profiling upon entering + certain functions and to disable profiling of some other functions. + + The result of basic-block profiling will be written to a file `bb.out'. + If the -ax option is used parameters for the profiling will be read + from file `bb.in'. + +*/ + +/* The following macro shall output assembler code to FILE + to initialize basic-block profiling. + + If profile_block_flag == 2 + + Output code to call the subroutine `__bb_init_trace_func' + and pass two parameters to it. The first parameter is + the address of a block allocated in the object module. + The second parameter is the number of the first basic block + of the function. + + The name of the block is a local symbol made with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + The number of the first basic block of the function is + passed to the macro in BLOCK_OR_LABEL. + + If described in a virtual assembler language the code to be + output looks like: + + parameter1 <- LPBX0 + parameter2 <- BLOCK_OR_LABEL + call __bb_init_trace_func + + else if profile_block_flag != 0 + + Output code to call the subroutine `__bb_init_func' + and pass one single parameter to it, which is the same + as the first parameter to `__bb_init_trace_func'. + + The first word of this parameter is a flag which will be nonzero if + the object module has already been initialized. So test this word + first, and do not call `__bb_init_func' if the flag is nonzero. + Note: When profile_block_flag == 2 the test need not be done + but `__bb_init_trace_func' *must* be called. + + BLOCK_OR_LABEL may be used to generate a label number as a + branch destination in case `__bb_init_func' will not be called. + + If described in a virtual assembler language the code to be + output looks like: + + cmp (LPBX0),0 + jne local_label + parameter1 <- LPBX0 + call __bb_init_func +local_label: + +*/ + +#undef FUNCTION_BLOCK_PROFILER +#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \ +do \ + { \ + static int num_func = 0; \ + rtx xops[8]; \ + char block_table[80], false_label[80]; \ + \ + ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \ + \ + xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \ + xops[5] = stack_pointer_rtx; \ + xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \ + \ + CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \ + \ + switch (profile_block_flag) \ + { \ + \ + case 2: \ + \ + xops[2] = GEN_INT ((BLOCK_OR_LABEL)); \ + xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func")); \ + xops[6] = GEN_INT (8); \ + \ + output_asm_insn (AS1(push%L2,%2), xops); \ + if (!flag_pic) \ + output_asm_insn (AS1(push%L1,%1), xops); \ + else \ + { \ + output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \ + output_asm_insn (AS1 (push%L7,%7), xops); \ + } \ + \ + output_asm_insn (AS1(call,%P3), xops); \ + output_asm_insn (AS2(add%L0,%6,%5), xops); \ + \ + break; \ + \ + default: \ + \ + ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \ + \ + xops[0] = const0_rtx; \ + xops[2] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, false_label)); \ + xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_func")); \ + xops[4] = gen_rtx_MEM (Pmode, xops[1]); \ + xops[6] = GEN_INT (4); \ + \ + CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \ + \ + output_asm_insn (AS2(cmp%L4,%0,%4), xops); \ + output_asm_insn (AS1(jne,%2), xops); \ + \ + if (!flag_pic) \ + output_asm_insn (AS1(push%L1,%1), xops); \ + else \ + { \ + output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \ + output_asm_insn (AS1 (push%L7,%7), xops); \ + } \ + \ + output_asm_insn (AS1(call,%P3), xops); \ + output_asm_insn (AS2(add%L0,%6,%5), xops); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "LPBZ", num_func); \ + num_func++; \ + \ + break; \ + \ + } \ + } \ +while (0) + +/* The following macro shall output assembler code to FILE + to increment a counter associated with basic block number BLOCKNO. + + If profile_block_flag == 2 + + Output code to initialize the global structure `__bb' and + call the function `__bb_trace_func' which will increment the + counter. + + `__bb' consists of two words. In the first word the number + of the basic block has to be stored. In the second word + the address of a block allocated in the object module + has to be stored. + + The basic block number is given by BLOCKNO. + + The address of the block is given by the label created with + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); + + by FUNCTION_BLOCK_PROFILER. + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + If described in a virtual assembler language the code to be + output looks like: + + move BLOCKNO -> (__bb) + move LPBX0 -> (__bb+4) + call __bb_trace_func + + Note that function `__bb_trace_func' must not change the + machine state, especially the flag register. To grant + this, you must output code to save and restore registers + either in this macro or in the macros MACHINE_STATE_SAVE + and MACHINE_STATE_RESTORE. The last two macros will be + used in the function `__bb_trace_func', so you must make + sure that the function prologue does not change any + register prior to saving it with MACHINE_STATE_SAVE. + + else if profile_block_flag != 0 + + Output code to increment the counter directly. + Basic blocks are numbered separately from zero within each + compiled object module. The count associated with block number + BLOCKNO is at index BLOCKNO in an array of words; the name of + this array is a local symbol made with this statement: + + ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2); + + Of course, since you are writing the definition of + `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you + can take a short cut in the definition of this macro and use the + name that you know will result. + + If described in a virtual assembler language the code to be + output looks like: + + inc (LPBX2+4*BLOCKNO) + +*/ + +#define BLOCK_PROFILER(FILE, BLOCKNO) \ +do \ + { \ + rtx xops[8], cnt_rtx; \ + char counts[80]; \ + char *block_table = counts; \ + \ + switch (profile_block_flag) \ + { \ + \ + case 2: \ + \ + ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \ + \ + xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \ + xops[2] = GEN_INT ((BLOCKNO)); \ + xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func")); \ + xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb"); \ + xops[5] = plus_constant (xops[4], 4); \ + xops[0] = gen_rtx_MEM (SImode, xops[4]); \ + xops[6] = gen_rtx_MEM (SImode, xops[5]); \ + \ + CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \ + \ + fprintf(FILE, "\tpushf\n"); \ + output_asm_insn (AS2(mov%L0,%2,%0), xops); \ + if (flag_pic) \ + { \ + xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \ + output_asm_insn (AS1(push%L7,%7), xops); \ + output_asm_insn (AS2(lea%L7,%a1,%7), xops); \ + output_asm_insn (AS2(mov%L6,%7,%6), xops); \ + output_asm_insn (AS1(pop%L7,%7), xops); \ + } \ + else \ + output_asm_insn (AS2(mov%L6,%1,%6), xops); \ + output_asm_insn (AS1(call,%P3), xops); \ + fprintf(FILE, "\tpopf\n"); \ + \ + break; \ + \ + default: \ + \ + ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \ + cnt_rtx = gen_rtx_SYMBOL_REF (VOIDmode, counts); \ + SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \ + \ + if (BLOCKNO) \ + cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \ + \ + if (flag_pic) \ + cnt_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, cnt_rtx); \ + \ + xops[0] = gen_rtx_MEM (SImode, cnt_rtx); \ + output_asm_insn (AS1(inc%L0,%0), xops); \ + \ + break; \ + \ + } \ + } \ +while (0) + +/* The following macro shall output assembler code to FILE + to indicate a return from function during basic-block profiling. + + If profiling_block_flag == 2: + + Output assembler code to call function `__bb_trace_ret'. + + Note that function `__bb_trace_ret' must not change the + machine state, especially the flag register. To grant + this, you must output code to save and restore registers + either in this macro or in the macros MACHINE_STATE_SAVE_RET + and MACHINE_STATE_RESTORE_RET. The last two macros will be + used in the function `__bb_trace_ret', so you must make + sure that the function prologue does not change any + register prior to saving it with MACHINE_STATE_SAVE_RET. + + else if profiling_block_flag != 0: + + The macro will not be used, so it need not distinguish + these cases. +*/ + +#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \ +do \ + { \ + rtx xops[1]; \ + \ + xops[0] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_ret")); \ + \ + output_asm_insn (AS1(call,%P0), xops); \ + \ + } \ +while (0) + +/* The function `__bb_trace_func' is called in every basic block + and is not allowed to change the machine state. Saving (restoring) + the state can either be done in the BLOCK_PROFILER macro, + before calling function (rsp. after returning from function) + `__bb_trace_func', or it can be done inside the function by + defining the macros: + + MACHINE_STATE_SAVE(ID) + MACHINE_STATE_RESTORE(ID) + + In the latter case care must be taken, that the prologue code + of function `__bb_trace_func' does not already change the + state prior to saving it with MACHINE_STATE_SAVE. + + The parameter `ID' is a string identifying a unique macro use. + + On the i386 the initialization code at the begin of + function `__bb_trace_func' contains a `sub' instruction + therefore we handle save and restore of the flag register + in the BLOCK_PROFILER macro. */ + +#define MACHINE_STATE_SAVE(ID) \ + asm (" pushl %eax"); \ + asm (" pushl %ecx"); \ + asm (" pushl %edx"); \ + asm (" pushl %esi"); + +#define MACHINE_STATE_RESTORE(ID) \ + asm (" popl %esi"); \ + asm (" popl %edx"); \ + asm (" popl %ecx"); \ + asm (" popl %eax"); + +/* 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. */ +/* Note on the 386 it might be more efficient not to define this since + we have to restore it ourselves from the frame pointer, in order to + use pop */ + +#define EXIT_IGNORE_STACK 1 + +/* This macro generates the assembly code for function exit, + on machines that need it. If FUNCTION_EPILOGUE is not defined + then individual return instructions are generated for each + return statement. Args are same as for FUNCTION_PROLOGUE. + + The function epilogue should not depend on the current stack pointer! + 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. + + If the last non-note insn in the function is a BARRIER, then there + is no need to emit a function prologue, because control does not fall + off the end. This happens if the function ends in an "exit" call, or + if a `return' insn is emitted directly into the function. */ + +#if 0 +#define FUNCTION_BEGIN_EPILOGUE(FILE) \ +do { \ + rtx last = get_last_insn (); \ + if (last && GET_CODE (last) == NOTE) \ + last = prev_nonnote_insn (last); \ +/* if (! last || GET_CODE (last) != BARRIER) \ + function_epilogue (FILE, SIZE);*/ \ +} while (0) +#endif + +#define FUNCTION_EPILOGUE(FILE, SIZE) \ + function_epilogue (FILE, SIZE) + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. */ + +/* On the 386, the trampoline contains two instructions: + mov #STATIC,ecx + jmp FUNCTION + The trampoline is generated entirely at runtime. The operand of JMP + is the address of FUNCTION relative to the instruction following the + JMP (which is 5 bytes long). */ + +/* Length in units of the trampoline for entering a nested function. */ + +#define TRAMPOLINE_SIZE 10 + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ + +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +{ \ + /* Compute offset from the end of the jmp to the target function. */ \ + rtx disp = expand_binop (SImode, sub_optab, FNADDR, \ + plus_constant (TRAMP, 10), \ + NULL_RTX, 1, OPTAB_DIRECT); \ + emit_move_insn (gen_rtx_MEM (QImode, TRAMP), GEN_INT (0xb9)); \ + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 1)), CXT); \ + emit_move_insn (gen_rtx_MEM (QImode, plus_constant (TRAMP, 5)), GEN_INT (0xe9));\ + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 6)), disp); \ +} + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the i386. First, the + frame pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the argument pointer register can always be + eliminated; it is replaced with either the stack or frame pointer. */ + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + For the i386, if frame pointer elimination is being done, we would like to + convert ap into sp, not fp. + + All other eliminations are valid. */ + +#define CAN_ELIMINATE(FROM, TO) \ + ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \ + ? ! frame_pointer_needed \ + : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ +{ \ + if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \ + (OFFSET) = 8; /* Skip saved PC and previous frame pointer */ \ + else \ + { \ + int nregs; \ + int offset; \ + int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; \ + HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), \ + &nregs); \ + \ + (OFFSET) = (tsize + nregs * UNITS_PER_WORD); \ + \ + offset = 4; \ + if (frame_pointer_needed) \ + offset += UNITS_PER_WORD; \ + \ + if ((FROM) == ARG_POINTER_REGNUM) \ + (OFFSET) += offset; \ + else \ + (OFFSET) -= ((offset + preferred_alignment - 1) \ + & -preferred_alignment) - offset; \ + } \ +} + +/* Addressing modes, and classification of registers for them. */ + +/* #define HAVE_POST_INCREMENT 0 */ +/* #define HAVE_POST_DECREMENT 0 */ + +/* #define HAVE_PRE_DECREMENT 0 */ +/* #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) < STACK_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] < STACK_POINTER_REGNUM) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) <= STACK_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO] <= STACK_POINTER_REGNUM) + +#define REGNO_OK_FOR_SIREG_P(REGNO) ((REGNO) == 4 || reg_renumber[REGNO] == 4) +#define REGNO_OK_FOR_DIREG_P(REGNO) ((REGNO) == 5 || reg_renumber[REGNO] == 5) + +/* 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. */ + + +/* Non strict versions, pseudos are ok */ +#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \ + (REGNO (X) < STACK_POINTER_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_OK_FOR_BASE_NONSTRICT_P(X) \ + (REGNO (X) <= STACK_POINTER_REGNUM \ + || REGNO (X) == ARG_POINTER_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_OK_FOR_STRREG_NONSTRICT_P(X) \ + (REGNO (X) == 4 || REGNO (X) == 5 || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +/* Strict versions, hard registers only */ +#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) +#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) +#define REG_OK_FOR_STRREG_STRICT_P(X) \ + (REGNO_OK_FOR_DIREG_P (REGNO (X)) || REGNO_OK_FOR_SIREG_P (REGNO (X))) + +#ifndef REG_OK_STRICT +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X) +#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_NONSTRICT_P(X) + +#else +#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P(X) +#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X) +#define REG_OK_FOR_STRREG_P(X) REG_OK_FOR_STRREG_STRICT_P(X) +#endif + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + + The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS, + except for CONSTANT_ADDRESS_P which is usually machine-independent. + + See legitimize_pic_address in i386.c for details as to what + constitutes a legitimate address when -fpic is used. */ + +#define MAX_REGS_PER_ADDRESS 2 + +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST) + +/* 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) \ + (GET_CODE (X) == CONST_DOUBLE ? standard_80387_constant_p (X) : 1) + +#ifdef REG_OK_STRICT +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (legitimate_address_p (MODE, X, 1)) \ + goto ADDR; \ +} + +#else +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ +{ \ + if (legitimate_address_p (MODE, X, 0)) \ + goto ADDR; \ +} + +#endif + +/* 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 80386, we handle X+REG by loading X into a register R and + using R+REG. R will go in a general 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 a general reg. + + When -fpic is used, special handling is needed for symbolic references. + See comments by legitimize_pic_address in i386.c for details. */ + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + (X) = legitimize_address (X, OLDX, MODE); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ +} + +#define REWRITE_ADDRESS(x) rewrite_address(x) + +/* 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_CONST (X) || legitimate_pic_address_disp_p (X)) + +#define SYMBOLIC_CONST(X) \ +(GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X))) + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. + On the 80386, only postdecrement 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) == POST_DEC) goto LABEL + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol + so that we may access it directly in the GOT. */ + +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + \ + if (TARGET_DEBUG_ADDR \ + && TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd') \ + { \ + fprintf (stderr, "Encode %s, public = %d\n", \ + IDENTIFIER_POINTER (DECL_NAME (DECL)), \ + TREE_PUBLIC (DECL)); \ + } \ + \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + } \ +while (0) + +/* Initialize data used by insn expanders. This is called from + init_emit, once for each function, before code is generated. + For 386, clear stack slot assignments remembered from previous + functions. */ + +#define INIT_EXPANDERS clear_386_stack_locals () + +/* The `FINALIZE_PIC' macro serves as a hook to emit these special + codes once the function is being compiled into assembly code, but + not before. (It is not done before, because in the case of + compiling an inline function, it would lead to multiple PIC + prologues being included in functions which used inline functions + and were compiled to assembly language.) */ + +#define FINALIZE_PIC \ +do \ + { \ + extern int current_function_uses_pic_offset_table; \ + \ + current_function_uses_pic_offset_table |= profile_flag | profile_block_flag; \ + } \ +while (0) + + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ + +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \ + (i386_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ + +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \ + (i386_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS)) + +/* If defined, a C expression whose value is zero if the attributes on + TYPE1 and TYPE2 are incompatible, one if they are compatible, and + two if they are nearly compatible (which causes a warning to be + generated). */ + +#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ + (i386_comp_type_attributes (TYPE1, TYPE2)) + +/* If defined, a C statement that assigns default attributes to newly + defined TYPE. */ + +/* #define SET_DEFAULT_TYPE_ATTRIBUTES (TYPE) */ + +/* Max number of args passed in registers. If this is more than 3, we will + have problems with ebx (register #4), since it is a caller save register and + is also used as the pic register in ELF. So for now, don't allow more than + 3 registers to be passed in registers. */ + +#define REGPARM_MAX 3 + + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE Pmode + +/* 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. + This should be changed to take advantage of fist --wfs ?? + */ +#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR + +/* This is the kind of divide that is easiest to do in the general case. */ +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 1 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* If a memory-to-memory move would take MOVE_RATIO or more simple + move-instruction pairs, we will do a movstr or libcall instead. + Increasing the value will always make code faster, but eventually + incurs high cost in increased code size. + + If you don't define this, a reasonable default is used. + + Make this large on i386, since the block move is very inefficient with small + blocks, and the hard register needs of the block move require much reload + work. */ + +#define MOVE_RATIO 5 + +/* Define if shifts truncate the shift count + which implies one can omit a sign-extension or zero-extension + of a shift count. */ +/* On i386, shifts do truncate the count. But bit opcodes don't. */ + +/* #define SHIFT_COUNT_TRUNCATED */ + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ + +#define STORE_FLAG_VALUE 1 + +/* When a prototype says `char' or `short', really pass an `int'. + (The 386 can't easily push less than 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 + +/* A part of a C `switch' statement that describes the relative costs + of constant RTL expressions. It must contain `case' labels for + expression codes `const_int', `const', `symbol_ref', `label_ref' + and `const_double'. Each case must ultimately reach a `return' + statement to return the relative cost of the use of that kind of + constant value in an expression. The cost may depend on the + precise value of the constant, which is available for examination + in X, and the rtx code of the expression in which it is contained, + found in OUTER_CODE. + + CODE is the expression code--redundant, since it can be obtained + with `GET_CODE (X)'. */ + +#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ + case CONST_INT: \ + return (unsigned) INTVAL (RTX) < 256 ? 0 : 1; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 1; \ + \ + case CONST_DOUBLE: \ + { \ + int code; \ + if (GET_MODE (RTX) == VOIDmode) \ + return 2; \ + \ + code = standard_80387_constant_p (RTX); \ + return code == 1 ? 0 : \ + code == 2 ? 1 : \ + 2; \ + } + +/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */ +#define TOPLEVEL_COSTS_N_INSNS(N) {total = COSTS_N_INSNS (N); break;} + +/* Like `CONST_COSTS' but applies to nonconstant RTL expressions. + This can be used, for example, to indicate how costly a multiply + instruction is. In writing this macro, you can use the construct + `COSTS_N_INSNS (N)' to specify a cost equal to N fast + instructions. OUTER_CODE is the code of the expression in which X + is contained. + + This macro is optional; do not define it if the default cost + assumptions are adequate for the target machine. */ + +#define RTX_COSTS(X,CODE,OUTER_CODE) \ + case ASHIFT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT \ + && GET_MODE (XEXP (X, 0)) == SImode) \ + { \ + HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \ + \ + if (value == 1) \ + return COSTS_N_INSNS (ix86_cost->add) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + \ + if (value == 2 || value == 3) \ + return COSTS_N_INSNS (ix86_cost->lea) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + } \ + /* fall through */ \ + \ + case ROTATE: \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ROTATERT: \ + if (GET_MODE (XEXP (X, 0)) == DImode) \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + if (INTVAL (XEXP (X, 1)) > 32) \ + return COSTS_N_INSNS(ix86_cost->shift_const + 2); \ + return COSTS_N_INSNS(ix86_cost->shift_const * 2); \ + } \ + return ((GET_CODE (XEXP (X, 1)) == AND \ + ? COSTS_N_INSNS(ix86_cost->shift_var * 2) \ + : COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2)) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE)); \ + } \ + return COSTS_N_INSNS (GET_CODE (XEXP (X, 1)) == CONST_INT \ + ? ix86_cost->shift_const \ + : ix86_cost->shift_var) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + \ + case MULT: \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + { \ + unsigned HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \ + int nbits = 0; \ + \ + if (value == 2) \ + return COSTS_N_INSNS (ix86_cost->add) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + if (value == 4 || value == 8) \ + return COSTS_N_INSNS (ix86_cost->lea) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + \ + while (value != 0) \ + { \ + nbits++; \ + value >>= 1; \ + } \ + \ + if (nbits == 1) \ + return COSTS_N_INSNS (ix86_cost->shift_const) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + \ + return COSTS_N_INSNS (ix86_cost->mult_init \ + + nbits * ix86_cost->mult_bit) \ + + rtx_cost(XEXP (X, 0), OUTER_CODE); \ + } \ + \ + else /* This is arbitrary */ \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \ + + 7 * ix86_cost->mult_bit); \ + \ + case DIV: \ + case UDIV: \ + case MOD: \ + case UMOD: \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->divide); \ + \ + case PLUS: \ + if (GET_CODE (XEXP (X, 0)) == REG \ + && GET_MODE (XEXP (X, 0)) == SImode \ + && GET_CODE (XEXP (X, 1)) == PLUS) \ + return COSTS_N_INSNS (ix86_cost->lea); \ + \ + /* fall through */ \ + case AND: \ + case IOR: \ + case XOR: \ + case MINUS: \ + if (GET_MODE (X) == DImode) \ + return COSTS_N_INSNS (ix86_cost->add) * 2 \ + + (rtx_cost (XEXP (X, 0), OUTER_CODE) \ + << (GET_MODE (XEXP (X, 0)) != DImode)) \ + + (rtx_cost (XEXP (X, 1), OUTER_CODE) \ + << (GET_MODE (XEXP (X, 1)) != DImode)); \ + case NEG: \ + case NOT: \ + if (GET_MODE (X) == DImode) \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->add) + + +/* An expression giving the cost of an addressing mode that contains + ADDRESS. If not defined, the cost is computed from the ADDRESS + expression and the `CONST_COSTS' values. + + For most CISC machines, the default cost is a good approximation + of the true cost of the addressing mode. However, on RISC + machines, all instructions normally have the same length and + execution time. Hence all addresses will have equal costs. + + In cases where more than one form of an address is known, the form + with the lowest cost will be used. If multiple forms have the + same, lowest, cost, the one that is the most complex will be used. + + For example, suppose an address that is equal to the sum of a + register and a constant is used twice in the same basic block. + When this macro is not defined, the address will be computed in a + register and memory references will be indirect through that + register. On machines where the cost of the addressing mode + containing the sum is no higher than that of a simple indirect + reference, this will produce an additional instruction and + possibly require an additional register. Proper specification of + this macro eliminates this overhead for such machines. + + Similar use of this macro is made in strength reduction of loops. + + ADDRESS need not be valid as an address. In such a case, the cost + is not relevant and can be any value; invalid addresses need not be + assigned a different cost. + + On machines where an address involving more than one register is as + cheap as an address computation involving only one register, + defining `ADDRESS_COST' to reflect this can cause two registers to + be live over a region of code where only one would have been if + `ADDRESS_COST' were not defined in that manner. This effect should + be considered in the definition of this macro. Equivalent costs + should probably only be given to addresses with different numbers + of registers on machines with lots of registers. + + This macro will normally either not be defined or be defined as a + constant. + + For i386, it is better to use a complex address than let gcc copy + the address into a reg and make a new pseudo. But not if the address + requires to two regs - that would mean more pseudos with longer + lifetimes. */ + +#define ADDRESS_COST(RTX) \ + ((CONSTANT_P (RTX) \ + || (GET_CODE (RTX) == PLUS && CONSTANT_P (XEXP (RTX, 1)) \ + && REG_P (XEXP (RTX, 0)))) ? 0 \ + : REG_P (RTX) ? 1 \ + : 2) + +/* A C expression for the cost of moving data of mode M between a + register and memory. A value of 2 is the default; this cost is + relative to those in `REGISTER_MOVE_COST'. + + If moving between registers and memory is more expensive than + between two registers, you should define this macro to express the + relative cost. + + On the i386, copying between floating-point and fixed-point + registers is expensive. */ + +#define REGISTER_MOVE_COST(CLASS1, CLASS2) \ + (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \ + || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10 \ + : 2) + + +/* A C expression for the cost of moving data of mode M between a + register and memory. A value of 2 is the default; this cost is + relative to those in `REGISTER_MOVE_COST'. + + If moving between registers and memory is more expensive than + between two registers, you should define this macro to express the + relative cost. */ + +/* #define MEMORY_MOVE_COST(M,C,I) 2 */ + +/* A C expression for the cost of a branch instruction. A value of 1 + is the default; other values are interpreted relative to that. */ + +#define BRANCH_COST i386_branch_cost + +/* Define this macro as a C expression which is nonzero if accessing + less than a word of memory (i.e. a `char' or a `short') is no + faster than accessing a word of memory, i.e., if such access + require more than one instruction or if there is no difference in + cost between byte and (aligned) word loads. + + When this macro is not defined, the compiler will access a field by + finding the smallest containing object; when it is defined, a + fullword load will be used if alignment permits. Unless bytes + accesses are faster than word accesses, using word accesses is + preferable since it may eliminate subsequent memory access if + subsequent accesses occur to other fields in the same word of the + structure, but to different bytes. */ + +#define SLOW_BYTE_ACCESS 0 + +/* Nonzero if access to memory by shorts is slow and undesirable. */ +#define SLOW_SHORT_ACCESS 0 + +/* Define this macro if zero-extension (of a `char' or `short' to an + `int') can be done faster if the destination is a register that is + known to be zero. + + If you define this macro, you must have instruction patterns that + recognize RTL structures like this: + + (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...) + + and likewise for `HImode'. */ + +/* #define SLOW_ZERO_EXTEND */ + +/* Define this macro to be the value 1 if unaligned accesses have a + cost many times greater than aligned accesses, for example if they + are emulated in a trap handler. + + When this macro is non-zero, the compiler will act as if + `STRICT_ALIGNMENT' were non-zero when generating code for block + moves. This can cause significantly more instructions to be + produced. Therefore, do not set this macro non-zero if unaligned + accesses only add a cycle or two to the time for a memory access. + + If the value of this macro is always zero, it need not be defined. */ + +/* #define SLOW_UNALIGNED_ACCESS 0 */ + +/* Define this macro to inhibit strength reduction of memory + addresses. (On some machines, such strength reduction seems to do + harm rather than good.) */ + +/* #define DONT_REDUCE_ADDR */ + +/* Define this macro if it is as good or better to call a constant + function address than to call an address kept in a register. + + Desirable on the 386 because a CALL with a constant address is + faster than one with a register address. */ + +#define NO_FUNCTION_CSE + +/* Define this macro if it is as good or better for a function to call + itself with an explicit address than to call an address kept in a + register. */ + +#define NO_RECURSIVE_FUNCTION_CSE + +/* A C statement (sans semicolon) to update the integer variable COST + based on the relationship between INSN that is dependent on + DEP_INSN through the dependence LINK. The default is to make no + adjustment to COST. This can be used for example to specify to + the scheduler that an output- or anti-dependence does not incur + the same cost as a data-dependence. */ + +#define ADJUST_COST(insn,link,dep_insn,cost) \ + (cost) = x86_adjust_cost(insn, link, dep_insn, cost) + +#define ADJUST_BLOCKAGE(last_insn,insn,blockage) \ +{ \ + if (is_fp_store (last_insn) && is_fp_insn (insn) \ + && NEXT_INSN (last_insn) && NEXT_INSN (NEXT_INSN (last_insn)) \ + && NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn))) \ + && (GET_CODE (NEXT_INSN (last_insn)) == INSN) \ + && (GET_CODE (NEXT_INSN (NEXT_INSN (last_insn))) == JUMP_INSN) \ + && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) == NOTE) \ + && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) \ + == NOTE_INSN_LOOP_END)) \ + { \ + (blockage) = 3; \ + } \ +} + +#define ISSUE_RATE ((int)ix86_cpu > (int)PROCESSOR_I486 ? 2 : 1) + + +/* Add any extra modes needed to represent the condition code. + + For the i386, we need separate modes when floating-point equality + comparisons are being done. */ + +#define EXTRA_CC_MODES CCFPEQmode + +/* Define the names for the modes specified above. */ +#define EXTRA_CC_NAMES "CCFPEQ" + +/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, + return the mode to be used for the comparison. + + For floating-point equality comparisons, CCFPEQmode should be used. + VOIDmode should be used in all other cases. */ + +#define SELECT_CC_MODE(OP,X,Y) \ + (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \ + && ((OP) == EQ || (OP) == NE) ? CCFPEQmode : VOIDmode) + +/* Define the information needed to generate branch and scc insns. This is + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); + +/* 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 was actually from the 80387 and + we are testing eax directly (i.e. no sahf) */ +#define CC_TEST_AX 020000 + +/* Set if the cc value is actually in the 80387, so a floating point + conditional branch must be output. */ +#define CC_IN_80387 04000 + +/* Set if the CC value was stored in a nonstandard way, so that + the state of equality is indicated by zero in the carry bit. */ +#define CC_Z_IN_NOT_C 010000 + +/* Set if the CC value was actually from the 80387 and loaded directly + into the eflags instead of via eax/sahf. */ +#define CC_FCOMI 040000 + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) \ + notice_update_cc((EXP)) + +/* Output a signed jump insn. Use template NORMAL ordinarily, or + FLOAT following a floating point comparison. + Use NO_OV following an arithmetic insn that set the cc's + before a test insn that was deleted. + NO_OV may be zero, meaning final should reinsert the test insn + because the jump cannot be handled properly without it. */ + +#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \ +{ \ + if (cc_prev_status.flags & CC_IN_80387) \ + return FLOAT; \ + if (cc_prev_status.flags & CC_NO_OVERFLOW) \ + return NO_OV; \ + return NORMAL; \ +} + +/* Control the assembler format that we output, to the extent + this does not vary between assemblers. */ + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +/* In order to refer to the first 8 regs as 32 bit regs prefix an "e" + For non floating point regs, the following are the HImode names. + + For float regs, the stack top is sometimes referred to as "%st(0)" + instead of just "%st". PRINT_REG handles this with the "y" code. */ + +#define HI_REGISTER_NAMES \ +{"ax","dx","cx","bx","si","di","bp","sp", \ + "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","" } + +#define REGISTER_NAMES HI_REGISTER_NAMES + +/* Table of additional register names to use in user input. */ + +#define ADDITIONAL_REGISTER_NAMES \ +{ { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, \ + { "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, \ + { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \ + { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } } + +/* Note we are omitting these since currently I don't know how +to get gcc to use these, since they want the same but different +number as al, and ax. +*/ + +/* note the last four are not really qi_registers, but + the md will have to never output movb into one of them + only a movw . There is no movb into the last four regs */ + +#define QI_REGISTER_NAMES \ +{"al", "dl", "cl", "bl", "si", "di", "bp", "sp",} + +/* These parallel the array above, and can be used to access bits 8:15 + of regs 0 through 3. */ + +#define QI_HIGH_REGISTER_NAMES \ +{"ah", "dh", "ch", "bh", } + +/* How to renumber registers for dbx and gdb. */ + +/* {0,2,1,3,6,7,4,5,12,13,14,15,16,17} */ +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 : \ + (n) == 1 ? 2 : \ + (n) == 2 ? 1 : \ + (n) == 3 ? 3 : \ + (n) == 4 ? 6 : \ + (n) == 5 ? 7 : \ + (n) == 6 ? 4 : \ + (n) == 7 ? 5 : \ + (n) + 4) + +/* Before the prologue, RA is at 0(%esp). */ +#define INCOMING_RETURN_ADDR_RTX \ + gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM)) + +/* After the prologue, RA is at -4(AP) in the current frame. */ +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT(-4)))\ + : gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, (FRAME), GEN_INT(4)))) + +/* PC is dbx register 8; let's use that column for RA. */ +#define DWARF_FRAME_RETURN_COLUMN 8 + +/* Before the prologue, the top of the frame is at 4(%esp). */ +#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) \ + (assemble_name (FILE, NAME), fputs (":\n", FILE)) + +/* This is how to output an assembler line defining a `double' constant. */ + +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long l[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ + fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \ + } while (0) + +/* 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); \ + fprintf (FILE, "%s 0x%lx,0x%lx,0x%lx\n", ASM_LONG, 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), "%s 0x%lx\n", ASM_LONG, l); \ + } while (0) + +/* 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))) + + + +/* This is how to output an assembler line defining an `int' constant. */ + +#define ASM_OUTPUT_INT(FILE,VALUE) \ +( fprintf (FILE, "%s ", ASM_LONG), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* Likewise for `char' and `short' constants. */ +/* is this supposed to do align too?? */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "%s ", ASM_SHORT), \ + output_addr_const (FILE,(VALUE)), \ + putc('\n',FILE)) + +/* +#define ASM_OUTPUT_SHORT(FILE,VALUE) \ +( fprintf (FILE, "%s ", ASM_BYTE_OP), \ + output_addr_const (FILE,(VALUE)), \ + fputs (",", FILE), \ + output_addr_const (FILE,(VALUE)), \ + fputs (" >> 8\n",FILE)) +*/ + + +#define ASM_OUTPUT_CHAR(FILE,VALUE) \ +( fprintf (FILE, "%s ", ASM_BYTE_OP), \ + output_addr_const (FILE, (VALUE)), \ + putc ('\n', FILE)) + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE,VALUE) \ + fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (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) \ + fprintf (FILE, "\tpushl %%e%s\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, "\tpopl %%e%s\n", reg_names[REGNO]) + +/* This is how to output an element of a case-vector that is absolute. + */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "%s %s%d\n", ASM_LONG, LPREFIX, VALUE) + +/* This is how to output an element of a case-vector that is relative. + We don't use these on the 386 yet, because the ATT assembler can't do + forward reference the differences. + */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL) + +/* Define the parentheses used to group arithmetic operations + in assembler code. */ + +#define ASM_OPEN_PAREN "" +#define ASM_CLOSE_PAREN "" + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 + +/* Print 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. + The CODE z takes the size of operand from the following digit, and + outputs b,w,or l respectively. + + On the 80386, we use several such letters: + f -- float insn (print a CONST_DOUBLE as a float rather than in hex). + L,W,B,Q,S,T -- print the opcode suffix for specified size of operand. + R -- print the prefix for register names. + z -- print the opcode suffix for the size of the current operand. + * -- print a star (in certain assembler syntax) + P -- if PIC, print an @PLT suffix. + X -- don't print any sort of PIC '@' suffix for a symbol. + J -- print jump insn for arithmetic_comparison_operator. + s -- ??? something to do with double shifts. not actually used, afaik. + C -- print a conditional move suffix corresponding to the op code. + c -- likewise, but reverse the condition. + F,f -- likewise, but for floating-point. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '*' || (CODE) == '_') + +/* Print the name of a register based on its machine mode and number. + If CODE is 'w', pretend the mode is HImode. + If CODE is 'b', pretend the mode is QImode. + If CODE is 'k', pretend the mode is SImode. + If CODE is 'h', pretend the reg is the `high' byte register. + If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */ + +extern char *hi_reg_name[]; +extern char *qi_reg_name[]; +extern char *qi_high_reg_name[]; + +#define PRINT_REG(X, CODE, FILE) \ + do { if (REGNO (X) == ARG_POINTER_REGNUM) \ + abort (); \ + fprintf (FILE, "%s", RP); \ + switch ((CODE == 'w' ? 2 \ + : CODE == 'b' ? 1 \ + : CODE == 'k' ? 4 \ + : CODE == 'y' ? 3 \ + : CODE == 'h' ? 0 \ + : GET_MODE_SIZE (GET_MODE (X)))) \ + { \ + case 3: \ + if (STACK_TOP_P (X)) \ + { \ + fputs ("st(0)", FILE); \ + break; \ + } \ + case 4: \ + case 8: \ + case 12: \ + if (! FP_REG_P (X)) fputs ("e", FILE); \ + case 2: \ + fputs (hi_reg_name[REGNO (X)], FILE); \ + break; \ + case 1: \ + fputs (qi_reg_name[REGNO (X)], FILE); \ + break; \ + case 0: \ + fputs (qi_high_reg_name[REGNO (X)], FILE); \ + break; \ + } \ + } while (0) + +#define PRINT_OPERAND(FILE, X, CODE) \ + print_operand (FILE, X, CODE) + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + print_operand_address (FILE, ADDR) + +/* Print the name of a register for based on its machine mode and number. + This macro is used to print debugging output. + This macro is different from PRINT_REG in that it may be used in + programs that are not linked with aux-output.o. */ + +#define DEBUG_PRINT_REG(X, CODE, FILE) \ + do { static char *hi_name[] = HI_REGISTER_NAMES; \ + static char *qi_name[] = QI_REGISTER_NAMES; \ + fprintf (FILE, "%d %s", REGNO (X), RP); \ + if (REGNO (X) == ARG_POINTER_REGNUM) \ + { fputs ("argp", FILE); break; } \ + if (STACK_TOP_P (X)) \ + { fputs ("st(0)", FILE); break; } \ + if (FP_REG_P (X)) \ + { fputs (hi_name[REGNO(X)], FILE); break; } \ + switch (GET_MODE_SIZE (GET_MODE (X))) \ + { \ + default: \ + fputs ("e", FILE); \ + case 2: \ + fputs (hi_name[REGNO (X)], FILE); \ + break; \ + case 1: \ + fputs (qi_name[REGNO (X)], FILE); \ + break; \ + } \ + } while (0) + +/* Output the prefix for an immediate operand, or for an offset operand. */ +#define PRINT_IMMED_PREFIX(FILE) fputs (IP, (FILE)) +#define PRINT_OFFSET_PREFIX(FILE) fputs (IP, (FILE)) + +/* Routines in libgcc that return floats must return them in an fp reg, + just as other functions do which return such values. + These macros make that happen. */ + +#define FLOAT_VALUE_TYPE float +#define INTIFY(FLOATVAL) FLOATVAL + +/* Nonzero if INSN magically clobbers register REGNO. */ + +/* #define INSN_CLOBBERS_REGNO_P(INSN, REGNO) \ + (FP_REGNO_P (REGNO) \ + && (GET_CODE (INSN) == JUMP_INSN || GET_CODE (INSN) == BARRIER)) +*/ + +/* a letter which is not needed by the normal asm syntax, which + we can use for operand syntax in the extended asm */ + +#define ASM_OPERAND_LETTER '#' +#define RET return "" +#define AT_SP(mode) (gen_rtx_MEM ((mode), stack_pointer_rtx)) + +/* Helper macros to expand a binary/unary operator if needed */ +#define IX86_EXPAND_BINARY_OPERATOR(OP, MODE, OPERANDS) \ +do { \ + if (!ix86_expand_binary_operator (OP, MODE, OPERANDS)) \ + FAIL; \ +} while (0) + +#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \ +do { \ + if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \ + FAIL; \ +} while (0) + + +/* Functions in i386.c */ +extern void override_options (); +extern void order_regs_for_local_alloc (); +extern char *output_strlen_unroll (); +extern struct rtx_def *i386_sext16_if_const (); +extern int i386_aligned_p (); +extern int i386_cc_probably_useless_p (); +extern int i386_valid_decl_attribute_p (); +extern int i386_valid_type_attribute_p (); +extern int i386_return_pops_args (); +extern int i386_comp_type_attributes (); +extern void init_cumulative_args (); +extern void function_arg_advance (); +extern struct rtx_def *function_arg (); +extern int function_arg_partial_nregs (); +extern char *output_strlen_unroll (); +extern char *singlemove_string (); +extern char *output_move_double (); +extern char *output_move_pushmem (); +extern int standard_80387_constant_p (); +extern char *output_move_const_single (); +extern int symbolic_operand (); +extern int call_insn_operand (); +extern int expander_call_insn_operand (); +extern int symbolic_reference_mentioned_p (); +extern int ix86_expand_binary_operator (); +extern int ix86_binary_operator_ok (); +extern int ix86_expand_unary_operator (); +extern int ix86_unary_operator_ok (); +extern void emit_pic_move (); +extern void function_prologue (); +extern int simple_386_epilogue (); +extern void function_epilogue (); +extern int legitimate_address_p (); +extern struct rtx_def *legitimize_pic_address (); +extern struct rtx_def *legitimize_address (); +extern void print_operand (); +extern void print_operand_address (); +extern void notice_update_cc (); +extern void split_di (); +extern int binary_387_op (); +extern int shift_op (); +extern int VOIDmode_compare_op (); +extern char *output_387_binary_op (); +extern char *output_fix_trunc (); +extern void output_float_extend (); +extern char *output_float_compare (); +extern char *output_fp_cc0_set (); +extern void save_386_machine_status (); +extern void restore_386_machine_status (); +extern void clear_386_stack_locals (); +extern struct rtx_def *assign_386_stack_local (); +extern int is_mul (); +extern int is_div (); +extern int last_to_set_cc (); +extern int doesnt_set_condition_code (); +extern int sets_condition_code (); +extern int str_immediate_operand (); +extern int is_fp_insn (); +extern int is_fp_dest (); +extern int is_fp_store (); +extern int agi_dependent (); +extern int reg_mentioned_in_mem (); +extern char *output_int_conditional_move (); +extern char *output_fp_conditional_move (); +extern int ix86_can_use_return_insn_p (); +extern int small_shift_operand (); +extern char *output_ashl (); +extern int memory_address_info (); + +#ifdef NOTYET +extern struct rtx_def *copy_all_rtx (); +extern void rewrite_address (); +#endif + +/* Variables in i386.c */ +extern char *ix86_cpu_string; /* for -mcpu=<xxx> */ +extern char *ix86_arch_string; /* for -march=<xxx> */ +extern char *i386_reg_alloc_order; /* register allocation order */ +extern char *i386_regparm_string; /* # registers to use to pass args */ +extern char *i386_align_loops_string; /* power of two alignment for loops */ +extern char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */ +extern char *i386_align_funcs_string; /* power of two alignment for functions */ +extern char *i386_preferred_stack_boundary_string;/* power of two alignment for stack boundary */ +extern char *i386_branch_cost_string; /* values 1-5: see jump.c */ +extern int i386_regparm; /* i386_regparm_string as a number */ +extern int i386_align_loops; /* power of two alignment for loops */ +extern int i386_align_jumps; /* power of two alignment for non-loop jumps */ +extern int i386_align_funcs; /* power of two alignment for functions */ +extern int i386_preferred_stack_boundary; /* preferred stack boundary alignment in bits */ +extern int i386_branch_cost; /* values 1-5: see jump.c */ +extern char *hi_reg_name[]; /* names for 16 bit regs */ +extern char *qi_reg_name[]; /* names for 8 bit regs (low) */ +extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */ +extern enum reg_class regclass_map[]; /* smalled class containing REGNO */ +extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */ +extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */ + +/* External variables used */ +extern int optimize; /* optimization level */ +extern int obey_regdecls; /* TRUE if stupid register allocation */ + +/* External functions used */ +extern struct rtx_def *force_operand (); + + +/* +Local variables: +version-control: t +End: +*/ diff --git a/gnu/egcs/gcc/config/i386/i386.md b/gnu/egcs/gcc/config/i386/i386.md new file mode 100644 index 00000000000..fb3e1b2ad0b --- /dev/null +++ b/gnu/egcs/gcc/config/i386/i386.md @@ -0,0 +1,8195 @@ +; GCC machine description for Intel X86. +;; Copyright (C) 1988, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. +;; Mostly by William Schelter. + +;; 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. */ + +;; 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. + +;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code +;; updates for most instructions. + +;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register +;; constraint letters. + +;; the special asm out single letter directives following a '%' are: +;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of +;; operands[1]. +;; 'L' Print the opcode suffix for a 32-bit integer opcode. +;; 'W' Print the opcode suffix for a 16-bit integer opcode. +;; 'B' Print the opcode suffix for an 8-bit integer opcode. +;; 'Q' Print the opcode suffix for a 64-bit float opcode. +;; 'S' Print the opcode suffix for a 32-bit float opcode. +;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode. +;; 'J' Print the appropriate jump operand. + +;; 'b' Print the QImode name of the register for the indicated operand. +;; %b0 would print %al if operands[0] is reg 0. +;; 'w' Likewise, print the HImode name of the register. +;; 'k' Likewise, print the SImode name of the register. +;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh. +;; 'y' Print "st(0)" instead of "st" as a register. + +;; UNSPEC usage: +;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode. +;; operand 0 is the memory address to scan. +;; operand 1 is a register containing the value to scan for. The mode +;; of the scas opcode will be the same as the mode of this operand. +;; operand 2 is the known alignment of operand 0. +;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT. +;; operand 0 is the argument for `sin'. +;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT. +;; operand 0 is the argument for `cos'. +;; 3 This is part of a `stack probe' operation. The mode of the UNSPEC is +;; always SImode. operand 0 is the size of the stack allocation. +;; 4 This is the source of a fake SET of the frame pointer which is used to +;; prevent insns referencing it being scheduled across the initial +;; decrement of the stack pointer. +;; 5 This is a `bsf' operation. +;; 6 This is the @GOT offset of a PIC address. +;; 7 This is the @GOTOFF offset of a PIC address. +;; 8 This is a reference to a symbol's @PLT address. + +;; This shadows the processor_type enumeration, so changes must be made +;; to i386.h at the same time. + +(define_attr "type" + "integer,binary,memory,test,compare,fcompare,idiv,imul,lea,fld,fpop,fpdiv,fpmul" + (const_string "integer")) + +(define_attr "memory" "none,load,store" + (cond [(eq_attr "type" "idiv,lea") + (const_string "none") + + (eq_attr "type" "fld") + (const_string "load") + + (eq_attr "type" "test") + (if_then_else (match_operand 0 "memory_operand" "") + (const_string "load") + (const_string "none")) + + (eq_attr "type" "compare,fcompare") + (if_then_else (ior (match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "")) + (const_string "load") + (const_string "none")) + + (and (eq_attr "type" "integer,memory,fpop") + (match_operand 0 "memory_operand" "")) + (const_string "store") + + (and (eq_attr "type" "integer,memory,fpop") + (match_operand 1 "memory_operand" "")) + (const_string "load") + + (and (eq_attr "type" "binary,imul,fpmul,fpdiv") + (ior (match_operand 1 "memory_operand" "") + (match_operand 2 "memory_operand" ""))) + (const_string "load")] + + (const_string "none"))) + +;; Functional units + +; (define_function_unit NAME MULTIPLICITY SIMULTANEITY +; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) + +; pentiumpro has a reservation station with 5 ports +; port 0 has integer, float add, integer divide, float divide, float +; multiply, and shifter units. +; port 1 has integer, and jump units. +; port 2 has the load address generation unit +; ports 3 and 4 have the store address generation units + +; pentium has two integer pipelines, the main u pipe and the secondary v pipe. +; and a float pipeline + +;; Floating point + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "i386,i486")) + 5 5) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "pentium,pentiumpro")) + 3 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium")) + 7 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro")) + 5 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro")) + 10 10) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro")) + 6 0) + +(define_function_unit "fp" 1 0 + (eq_attr "type" "fpdiv") + 10 10) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fld") (eq_attr "cpu" "!pentiumpro,k6")) + 1 0) + +;; K6 FPU is not pipelined. +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpop,fpmul,fcompare") (eq_attr "cpu" "k6")) + 2 2) + +;; i386 and i486 have one integer unit, which need not be modeled + +(define_function_unit "integer" 2 0 + (and (eq_attr "type" "integer,binary,test,compare,lea") (eq_attr "cpu" "pentium,pentiumpro")) + 1 0) + +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "k6") + (and (eq_attr "type" "integer,binary,test,compare") + (eq_attr "memory" "!load"))) + 1 0) + +;; Internally, K6 converts REG OP MEM instructions into a load (2 cycles) +;; and a register operation (1 cycle). +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "k6") + (and (eq_attr "type" "integer,binary,test,compare") + (eq_attr "memory" "load"))) + 3 0) + +;; Multiplies use one of the integer units +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "pentium") (eq_attr "type" "imul")) + 11 11) + +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "k6") (eq_attr "type" "imul")) + 2 2) + +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "pentium") (eq_attr "type" "idiv")) + 25 25) + +(define_function_unit "integer" 2 0 + (and (eq_attr "cpu" "k6") (eq_attr "type" "idiv")) + 17 17) + +;; Pentium Pro and K6 have a separate load unit. +(define_function_unit "load" 1 0 + (and (eq_attr "cpu" "pentiumpro") (eq_attr "memory" "load")) + 3 0) + +(define_function_unit "load" 1 0 + (and (eq_attr "cpu" "k6") (eq_attr "memory" "load")) + 2 0) + +;; Pentium Pro and K6 have a separate store unit. +(define_function_unit "store" 1 0 + (and (eq_attr "cpu" "pentiumpro,k6") (eq_attr "memory" "store")) + 1 0) + +;; lea executes in the K6 store unit with 1 cycle latency +(define_function_unit "store" 1 0 + (and (eq_attr "cpu" "k6") (eq_attr "type" "lea")) + 1 0) + + +;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM". +;; But restricting MEM here would mean that gcc could not remove a redundant +;; test in cases like "incl MEM / je TARGET". +;; +;; 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. + +;; All test insns have expanders that save the operands away without +;; actually generating RTL. The bCOND or sCOND (emitted immediately +;; after the tstM or cmp) will actually emit the tstM or cmpM. + +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in i386.h. + +(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6" + (const (symbol_ref "ix86_cpu"))) + +(define_insn "tstsi_1" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + if (REG_P (operands[0])) + return AS2 (test%L0,%0,%0); + + operands[1] = const0_rtx; + return AS2 (cmp%L0,%1,%0); +}" + [(set_attr "type" "test")]) + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tstsi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +(define_insn "tsthi_1" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + if (REG_P (operands[0])) + return AS2 (test%W0,%0,%0); + + operands[1] = const0_rtx; + return AS2 (cmp%W0,%1,%0); +}" + [(set_attr "type" "test")]) + +(define_expand "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tsthi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +(define_insn "tstqi_1" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" "qm"))] + "" + "* +{ + if (REG_P (operands[0])) + return AS2 (test%B0,%0,%0); + + operands[1] = const0_rtx; + return AS2 (cmp%B0,%1,%0); +}" + [(set_attr "type" "test")]) + +(define_expand "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tstqi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +(define_insn "tstsf_cc" + [(set (cc0) + (match_operand:SF 0 "register_operand" "f")) + (clobber (match_scratch:HI 1 "=a"))] + "TARGET_80387 && ! TARGET_IEEE_FP" + "* +{ + if (! STACK_TOP_P (operands[0])) + abort (); + + output_asm_insn (\"ftst\", operands); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp,%y0), operands); + + return output_fp_cc0_set (insn); +}" + [(set_attr "type" "test")]) + +;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. + +(define_expand "tstsf" + [(parallel [(set (cc0) + (match_operand:SF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstsf_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +(define_insn "tstdf_cc" + [(set (cc0) + (match_operand:DF 0 "register_operand" "f")) + (clobber (match_scratch:HI 1 "=a"))] + "TARGET_80387 && ! TARGET_IEEE_FP" + "* +{ + if (! STACK_TOP_P (operands[0])) + abort (); + + output_asm_insn (\"ftst\", operands); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp,%y0), operands); + + return output_fp_cc0_set (insn); +}" + [(set_attr "type" "test")]) + +;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. + +(define_expand "tstdf" + [(parallel [(set (cc0) + (match_operand:DF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstdf_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +(define_insn "tstxf_cc" + [(set (cc0) + (match_operand:XF 0 "register_operand" "f")) + (clobber (match_scratch:HI 1 "=a"))] + "TARGET_80387 && ! TARGET_IEEE_FP" + "* +{ + if (! STACK_TOP_P (operands[0])) + abort (); + + output_asm_insn (\"ftst\", operands); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp,%y0), operands); + + return output_fp_cc0_set (insn); +}" + [(set_attr "type" "test")]) + +;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. + +(define_expand "tstxf" + [(parallel [(set (cc0) + (match_operand:XF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstxf_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; + DONE; +}") + +;;- compare instructions. See comments above tstM patterns about +;; expansion of these insns. + +(define_insn "cmpsi_1" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "mr,r") + (match_operand:SI 1 "general_operand" "ri,mr")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* return AS2 (cmp%L0,%1,%0);" + [(set_attr "type" "compare")]) + +(define_expand "cmpsi" + [(set (cc0) + (compare (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[0] = force_reg (SImode, operands[0]); + + i386_compare_gen = gen_cmpsi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_insn "cmphi_1" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "mr,r") + (match_operand:HI 1 "general_operand" "ri,mr")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* return AS2 (cmp%W0,%1,%0);" + [(set_attr "type" "compare")]) + +(define_expand "cmphi" + [(set (cc0) + (compare (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[0] = force_reg (HImode, operands[0]); + + i386_compare_gen = gen_cmphi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_insn "cmpqi_1" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "q,mq") + (match_operand:QI 1 "general_operand" "qm,nq")))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" + "* return AS2 (cmp%B0,%1,%0);" + [(set_attr "type" "compare")]) + +(define_expand "cmpqi" + [(set (cc0) + (compare (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[0] = force_reg (QImode, operands[0]); + + i386_compare_gen = gen_cmpqi_1; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +;; These implement float point compares. For each of DFmode and +;; SFmode, there is the normal insn, and an insn where the second operand +;; is converted to the desired mode. + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (float_extend:XF + (match_operand:DF 1 "nonimmediate_operand" "fm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:XF + (match_operand:DF 0 "nonimmediate_operand" "fm")) + (match_operand:XF 1 "register_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (float_extend:XF + (match_operand:SF 1 "nonimmediate_operand" "fm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:XF + (match_operand:SF 0 "nonimmediate_operand" "fm")) + (match_operand:XF 1 "register_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (compare:CCFPEQ (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f"))) + (clobber (match_scratch:HI 2 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:DF 0 "nonimmediate_operand" "f,fm") + (match_operand:DF 1 "nonimmediate_operand" "fm,f")])) + (clobber (match_scratch:HI 3 "=a,a"))] + "TARGET_80387 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:DF 0 "register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" "fm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:DF + (match_operand:SF 0 "nonimmediate_operand" "fm")) + (match_operand:DF 1 "register_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:DF + (match_operand:SF 0 "register_operand" "f")) + (match_operand:DF 1 "nonimmediate_operand" "fm")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f"))) + (clobber (match_scratch:HI 2 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +;; These two insns will never be generated by combine due to the mode of +;; the COMPARE. +;(define_insn "" +; [(set (cc0) +; (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") +; (float_extend:DF +; (match_operand:SF 1 "register_operand" "f")))) +; (clobber (match_scratch:HI 2 "=a"))] +; "TARGET_80387" +; "* return output_float_compare (insn, operands);") +; +;(define_insn "" +; [(set (cc0) +; (compare:CCFPEQ (float_extend:DF +; (match_operand:SF 0 "register_operand" "f")) +; (match_operand:DF 1 "register_operand" "f"))) +; (clobber (match_scratch:HI 2 "=a"))] +; "TARGET_80387" +; "* return output_float_compare (insn, operands);") + +(define_insn "*cmpsf_cc_1" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:SF 0 "nonimmediate_operand" "f,fm") + (match_operand:SF 1 "nonimmediate_operand" "fm,f")])) + (clobber (match_scratch:HI 3 "=a,a"))] + "TARGET_80387 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_insn "" + [(set (cc0) + (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f"))) + (clobber (match_scratch:HI 2 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);" + [(set_attr "type" "fcompare")]) + +(define_expand "cmpxf" + [(set (cc0) + (compare (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "register_operand" "")))] + "TARGET_80387" + " +{ + i386_compare_gen = gen_cmpxf_cc; + i386_compare_gen_eq = gen_cmpxf_ccfpeq; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_expand "cmpdf" + [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "general_operand" "")))] + "TARGET_80387" + " +{ + i386_compare_gen = gen_cmpdf_cc; + i386_compare_gen_eq = gen_cmpdf_ccfpeq; + i386_compare_op0 = operands[0]; + i386_compare_op1 = (immediate_operand (operands[1], DFmode)) + ? copy_to_mode_reg (DFmode, operands[1]) : operands[1]; + DONE; +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "general_operand" "")))] + "TARGET_80387" + " +{ + i386_compare_gen = gen_cmpsf_cc; + i386_compare_gen_eq = gen_cmpsf_ccfpeq; + i386_compare_op0 = operands[0]; + i386_compare_op1 = (immediate_operand (operands[1], SFmode)) + ? copy_to_mode_reg (SFmode, operands[1]) : operands[1]; + DONE; +}") + +(define_expand "cmpxf_cc" + [(parallel [(set (cc0) + (compare (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + "") + +(define_expand "cmpxf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + "") + +(define_expand "cmpdf_cc" + [(parallel [(set (cc0) + (compare (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + "") + +(define_expand "cmpdf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + " +{ + if (! register_operand (operands[1], DFmode)) + operands[1] = copy_to_mode_reg (DFmode, operands[1]); +}") + +(define_expand "cmpsf_cc" + [(parallel [(set (cc0) + (compare (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + "") + +(define_expand "cmpsf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + " +{ + if (! register_operand (operands[1], SFmode)) + operands[1] = copy_to_mode_reg (SFmode, operands[1]); +}") + +;; logical compare + +(define_insn "" + [(set (cc0) + (and:SI (match_operand:SI 0 "general_operand" "%ro") + (match_operand:SI 1 "nonmemory_operand" "ri")))] + "" + "* +{ + /* For small integers, we may actually use testb. */ + if (GET_CODE (operands[1]) == CONST_INT + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + && (! REG_P (operands[0]) || QI_REG_P (operands[0])) + /* A Pentium test is pairable only with eax. Not with ah or al. */ + && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM + || optimize_size)) + { + /* We may set the sign bit spuriously. */ + + if ((INTVAL (operands[1]) & ~0xff) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } + + if ((INTVAL (operands[1]) & ~0xff00) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (INTVAL (operands[1]) >> 8); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } + } + + if (GET_CODE (operands[0]) == MEM + && (INTVAL (operands[1]) & ~0xff0000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (INTVAL (operands[1]) >> 16); + operands[0] = adj_offsettable_operand (operands[0], 2); + return AS2 (test%B0,%1,%b0); + } + + if (GET_CODE (operands[0]) == MEM + && (INTVAL (operands[1]) & ~0xff000000) == 0) + { + operands[1] = GEN_INT ((INTVAL (operands[1]) >> 24) & 0xff); + operands[0] = adj_offsettable_operand (operands[0], 3); + return AS2 (test%B0,%1,%b0); + } + } + + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%L0,%1,%0); + + return AS2 (test%L1,%0,%1); +}" + [(set_attr "type" "compare")]) + +(define_insn "" + [(set (cc0) + (and:HI (match_operand:HI 0 "general_operand" "%ro") + (match_operand:HI 1 "nonmemory_operand" "ri")))] + "" + "* +{ + if (GET_CODE (operands[1]) == CONST_INT + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + && (! REG_P (operands[0]) || QI_REG_P (operands[0]))) + { + if ((INTVAL (operands[1]) & 0xff00) == 0) + { + /* ??? This might not be necessary. */ + if (INTVAL (operands[1]) & 0xffff0000) + operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); + + /* We may set the sign bit spuriously. */ + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } + + if ((INTVAL (operands[1]) & 0xff) == 0) + { + operands[1] = GEN_INT ((INTVAL (operands[1]) >> 8) & 0xff); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } + } + } + + /* use 32-bit test instruction if there are no sign issues */ + if (GET_CODE (operands[1]) == CONST_INT + && !(INTVAL (operands[1]) & ~0x7fff) + && i386_aligned_p (operands[0])) + return AS2 (test%L0,%1,%k0); + + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%W0,%1,%0); + + return AS2 (test%W1,%0,%1); +}" + [(set_attr "type" "compare")]) + +(define_insn "" + [(set (cc0) + (and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm") + (match_operand:QI 1 "nonmemory_operand" "qi")))] + "" + "* +{ + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%B0,%1,%0); + + return AS2 (test%B1,%0,%1); +}" + [(set_attr "type" "compare")]) + +;; move instructions. +;; There is one for each machine mode, +;; and each is preceded by a corresponding push-insn pattern +;; (since pushes are not general_operands on the 386). + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "nonmemory_operand" "rn"))] + "flag_pic" + "* return AS1 (push%L0,%1);" + [(set_attr "memory" "store")]) + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "nonmemory_operand" "ri"))] + "!flag_pic" + "* return AS1 (push%L0,%1);" + [(set_attr "memory" "store")]) + +;; On a 386, it is faster to push MEM directly. + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "memory_operand" "m"))] + "TARGET_PUSH_MEMORY" + "* return AS1 (push%L0,%1);" + [(set_attr "type" "memory") + (set_attr "memory" "load")]) + +;; General case of fullword move. + +;; If generating PIC code and operands[1] is a symbolic CONST, emit a +;; move to get the address of the symbolic object from the GOT. + +(define_expand "movsi" + [(set (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + " +{ + extern int flag_pic; + + if (flag_pic && SYMBOLIC_CONST (operands[1])) + emit_pic_move (operands, SImode); + + /* Don't generate memory->memory moves, go through a register */ + else if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (SImode, operands[1]); + } +}") + +;; On i486, incl reg is faster than movl $1,reg. + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g,r,r") + (match_operand:SI 1 "general_operand" "rn,i,m"))] + "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)) + && flag_pic" + "* +{ + rtx link; + + /* K6: mov reg,0 is slightly faster than xor reg,reg but is 3 bytes + longer. */ + if ((ix86_cpu != PROCESSOR_K6 || optimize_size) + && operands[1] == const0_rtx && REG_P (operands[0])) + return AS2 (xor%L0,%0,%0); + + if (operands[1] == const1_rtx + /* PPRO and K6 prefer mov to inc to reduce dependencies. */ + && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO) + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%L0,%0); + + if (SYMBOLIC_CONST (operands[1])) + return AS2 (lea%L0,%a1,%0); + + return AS2 (mov%L0,%1,%0); +}" + [(set_attr "type" "integer,integer,memory") + (set_attr "memory" "*,*,load")]) + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=g,r") + (match_operand:SI 1 "general_operand" "ri,m"))] + "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)) + && !flag_pic" + "* +{ + rtx link; + + /* Use of xor was disabled for AMD K6 as recommended by the Optimization + Manual. My test shows, that this generally hurts the performance, because + mov is longer and takes longer to decode and decoding is the main + bottleneck of K6 when executing GCC code. */ + + if (operands[1] == const0_rtx && REG_P (operands[0])) + return AS2 (xor%L0,%0,%0); + + if (operands[1] == const1_rtx + /* PPRO and K6 prefer mov to inc to reduce dependencies. */ + && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO) + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%L0,%0); + + return AS2 (mov%L0,%1,%0); +}" + [(set_attr "type" "integer,memory") + (set_attr "memory" "*,load")]) + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "nonmemory_operand" "ri"))] + "" + "* return AS1 (push%W0,%1);" + [(set_attr "type" "memory") + (set_attr "memory" "store")]) + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "memory_operand" "m"))] + "TARGET_PUSH_MEMORY" + "* return AS1 (push%W0,%1);" + [(set_attr "type" "memory") + (set_attr "memory" "load")]) + +;; On i486, an incl and movl are both faster than incw and movw. + +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (HImode, operands[1]); + } +}") + +(define_insn "" + [(set (match_operand:HI 0 "general_operand" "=g,r") + (match_operand:HI 1 "general_operand" "ri,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx link; + if (REG_P (operands[0]) && operands[1] == const0_rtx) + return AS2 (xor%L0,%k0,%k0); + + if (REG_P (operands[0]) && operands[1] == const1_rtx + /* PPRO and K6 prefer mov to inc to reduce dependencies. */ + && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO) + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%L0,%k0); + + if (REG_P (operands[0])) + { + if (i386_aligned_p (operands[1])) + { + operands[1] = i386_sext16_if_const (operands[1]); + return AS2 (mov%L0,%k1,%k0); + } + if (! TARGET_ZERO_EXTEND_WITH_AND) + { + /* movzwl is faster than movw on the Pentium Pro, + * although not as fast as an aligned movl. */ +#ifdef INTEL_SYNTAX + return AS2 (movzx,%1,%k0); +#else + return AS2 (movz%W0%L0,%1,%k0); +#endif + } + } + + return AS2 (mov%W0,%1,%0); +}" + [(set_attr "type" "integer,memory") + (set_attr "memory" "*,load")]) + +(define_expand "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "")) + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (HImode, operands[1]); + } +}") + +(define_insn "" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r")) + (match_operand:HI 1 "general_operand" "ri,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx link; + + /* Use of xor was disabled for AMD K6 as recommended by the Optimization + Manual. My test shows, that this generally hurts the performance, because + mov is longer and takes longer to decode and decoding is the main + bottleneck of K6 when executing GCC code. */ + + if (operands[1] == const0_rtx && REG_P (operands[0])) + return AS2 (xor%W0,%0,%0); + + if (operands[1] == const1_rtx + /* PPRO and K6 prefer mov to inc to reduce dependencies. */ + && (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO) + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%W0,%0); + + return AS2 (mov%W0,%1,%0); +}" + [(set_attr "type" "integer,memory")]) + +;; emit_push_insn when it calls move_by_pieces +;; requires an insn to "push a byte". +;; But actually we use pushw, which has the effect of rounding +;; the amount pushed up to a halfword. +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "const_int_operand" "n"))] + "" + "* return AS1(push%W0,%1);") + +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "register_operand" "q"))] + "" + "* +{ + operands[1] = gen_rtx_REG (HImode, REGNO (operands[1])); + return AS1 (push%W0,%1); +}") + +;; On i486, incb reg is faster than movb $1,reg. + +;; ??? Do a recognizer for zero_extract that looks just like this, but reads +;; or writes %ah, %bh, %ch, %dh. + +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (QImode, operands[1]); + } +}") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm") + (match_operand:QI 1 "general_operand" "*g,*rn,qn"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx link; + + /* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8. + It is at least as fast as xor on any processor except a Pentium. */ + + if (operands[1] == const1_rtx + && TARGET_PENTIUM + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + { + /* Fastest way to change a 0 to a 1. + If inc%B0 isn't allowed, use inc%L0. */ + if (NON_QI_REG_P (operands[0])) + return AS1 (inc%L0,%k0); + else + return AS1 (inc%B0,%0); + } + + /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */ + if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) + return (AS2 (mov%L0,%k1,%k0)); + + return (AS2 (mov%B0,%1,%0)); +}") + +;; If it becomes necessary to support movstrictqi into %esi or %edi, +;; use the insn sequence: +;; +;; shrdl $8,srcreg,dstreg +;; rorl $24,dstreg +;; +;; If operands[1] is a constant, then an andl/orl sequence would be +;; faster. + +(define_expand "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "")) + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (QImode, operands[1]); + } +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) + (match_operand:QI 1 "general_operand" "*qn,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx link; + + /* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8. */ + + if (operands[1] == const1_rtx + && TARGET_PENTIUM + && ! NON_QI_REG_P (operands[0]) + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%B0,%0); + + /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */ + if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) + { + abort (); + return (AS2 (mov%L0,%k1,%k0)); + } + + return AS2 (mov%B0,%1,%0); +}") + +(define_insn "movsf_push" + [(set (match_operand:SF 0 "push_operand" "=<,<") + (match_operand:SF 1 "general_operand" "*rfF,m"))] + "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM + || reload_in_progress || reload_completed" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + if (! STACK_TOP_P (operands[1])) + abort (); + + xops[0] = AT_SP (SFmode); + xops[1] = GEN_INT (4); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp%S0,%0), xops); + else + output_asm_insn (AS1 (fst%S0,%0), xops); + + RET; + } + + return AS1 (push%L0,%1); +}") + +(define_split + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "reload_completed && STACK_REG_P (operands[1])" + [(set (reg:SI 7) + (minus:SI (reg:SI 7) (const_int 4))) + (set (mem:SF (reg:SI 7)) + (match_dup 1))] + "") + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (SFmode, operands[1]); + } + + /* If we are loading a floating point constant that isn't 0 or 1 + into a register, force the value to memory now, since we'll + get better code out the back end. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); + } +}") + +;; For the purposes of regclass, prefer FLOAT_REGS. +(define_insn "" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r,!m") + (match_operand:SF 1 "general_operand" "fmG,f,*rmF,*rF"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + /* First handle a `pop' insn or a `fld %st(0)' */ + + if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp,%y0); + else + return AS1 (fld,%y0); + } + + /* Handle other kinds of writes from the 387 */ + + if (STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp%z0,%y0); + else + return AS1 (fst%z0,%y0); + } + + /* Handle other kinds of reads to the 387 */ + + if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + /* Handle all SFmode moves not involving the 387 */ + + return singlemove_string (operands); +}" + [(set_attr "type" "fld")]) + + +(define_insn "swapsf" + [(set (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f")) + (set (match_dup 1) + (match_dup 0))] + "" + "* +{ + if (STACK_TOP_P (operands[0])) + return AS1 (fxch,%1); + else + return AS1 (fxch,%0); +}") + + +(define_insn "movdf_push" + [(set (match_operand:DF 0 "push_operand" "=<,<") + (match_operand:DF 1 "general_operand" "*rfF,o"))] + "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM + || reload_in_progress || reload_completed" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + xops[0] = AT_SP (DFmode); + xops[1] = GEN_INT (8); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp%Q0,%0), xops); + else + output_asm_insn (AS1 (fst%Q0,%0), xops); + + RET; + } + + if (which_alternative == 1) + return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0); + + return output_move_double (operands); +}") + +(define_split + [(set (match_operand:DF 0 "push_operand" "") + (match_operand:DF 1 "register_operand" ""))] + "reload_completed && STACK_REG_P (operands[1])" + [(set (reg:SI 7) + (minus:SI (reg:SI 7) (const_int 8))) + (set (mem:DF (reg:SI 7)) + (match_dup 1))] + "") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (DFmode, operands[1]); + } + + /* If we are loading a floating point constant that isn't 0 or 1 into a + register, indicate we need the pic register loaded. This could be + optimized into stores of constants if the target eventually moves to + memory, but better safe than sorry. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + operands[1] = validize_mem (force_const_mem (DFmode, operands[1])); + } +}") + +;; For the purposes of regclass, prefer FLOAT_REGS. +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r,!o") + (match_operand:DF 1 "general_operand" "fmG,f,*roF,*rF"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + /* First handle a `pop' insn or a `fld %st(0)' */ + + if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp,%y0); + else + return AS1 (fld,%y0); + } + + /* Handle other kinds of writes from the 387 */ + + if (STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp%z0,%y0); + else + return AS1 (fst%z0,%y0); + } + + /* Handle other kinds of reads to the 387 */ + + if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + /* Handle all DFmode moves not involving the 387 */ + + return output_move_double (operands); +}" + [(set_attr "type" "fld")]) + + + +(define_insn "swapdf" + [(set (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f")) + (set (match_dup 1) + (match_dup 0))] + "" + "* +{ + if (STACK_TOP_P (operands[0])) + return AS1 (fxch,%1); + else + return AS1 (fxch,%0); +}") + +(define_insn "movxf_push" + [(set (match_operand:XF 0 "push_operand" "=<,<") + (match_operand:XF 1 "general_operand" "*rfF,o"))] + "TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM + || reload_in_progress || reload_completed" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + xops[0] = AT_SP (XFmode); + xops[1] = GEN_INT (12); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + + output_asm_insn (AS1 (fstp%T0,%0), xops); + if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fld%T0,%0), xops); + + RET; + } + + if (which_alternative == 1) + return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0); + + return output_move_double (operands); + }") + +(define_split + [(set (match_operand:XF 0 "push_operand" "") + (match_operand:XF 1 "register_operand" ""))] + "reload_completed && STACK_REG_P (operands[1])" + [(set (reg:SI 7) + (minus:SI (reg:SI 7) (const_int 12))) + (set (mem:XF (reg:SI 7)) + (match_dup 1))] + "") + +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (XFmode, operands[1]); + } + + /* If we are loading a floating point constant that isn't 0 or 1 + into a register, indicate we need the pic register loaded. This could + be optimized into stores of constants if the target eventually moves + to memory, but better safe than sorry. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + operands[1] = validize_mem (force_const_mem (XFmode, operands[1])); + } +}") + + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!*r,!o") + (match_operand:XF 1 "general_operand" "fmG,f,*roF,*rF"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + /* First handle a `pop' insn or a `fld %st(0)' */ + + if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp,%y0); + else + return AS1 (fld,%y0); + } + + /* Handle other kinds of writes from the 387 */ + + if (STACK_TOP_P (operands[1])) + { + output_asm_insn (AS1 (fstp%z0,%y0), operands); + if (! stack_top_dies) + return AS1 (fld%z0,%y0); + + RET; + } + + /* Handle other kinds of reads to the 387 */ + + if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + /* Handle all XFmode moves not involving the 387 */ + + return output_move_double (operands); +}") + +(define_insn "swapxf" + [(set (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")) + (set (match_dup 1) + (match_dup 0))] + "" + "* +{ + if (STACK_TOP_P (operands[0])) + return AS1 (fxch,%1); + else + return AS1 (fxch,%0); +}") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_operand" "riF"))] + "" + "* return output_move_double (operands);") + +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "memory_operand" "o"))] + "TARGET_PUSH_MEMORY" + "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode),0,0);") + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && no_new_pseudos == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (DImode, operands[1]); + } +}") + +(define_insn "" + [(set (match_operand:DI 0 "general_operand" "=g,r") + (match_operand:DI 1 "general_operand" "riF,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)" + "* return output_move_double (operands);" + [(set_attr "type" "integer,memory") + (set_attr "memory" "*,load")]) + +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "reload_completed + && (offsettable_memref_p (operands[0]) + || nonmemory_operand (operands[0], DImode)) + && (offsettable_memref_p (operands[1]) + || nonmemory_operand (operands[1], DImode)) + && (! reg_overlap_mentioned_p (gen_lowpart (SImode, operands[0]), + operands[1]) + || ! reg_overlap_mentioned_p (gen_highpart (SImode, operands[0]), + operands[1]))" + [(set (match_dup 2) + (match_dup 4)) + (set (match_dup 3) + (match_dup 5))] + " +{ + split_di (&operands[0], 1, &operands[2], &operands[3]); + split_di (&operands[1], 1, &operands[4], &operands[5]); + + if (reg_overlap_mentioned_p (operands[2], operands[1])) + { + rtx tmp; + + tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + + tmp = operands[4]; + operands[4] = operands[5]; + operands[5] = tmp; + } +}") + +;;- conversion instructions +;;- NONE + +;;- zero extension instructions +;; See comments by `andsi' for when andl is faster than movzx. + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + "") + +;; When optimizing for the PPro/PII or code size, always use movzwl. +;; We want to use a different pattern so we can use different constraints +;; than the generic pattern. +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "(optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)" + "* return AS2 (movz%W0%L0,%1,%0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,&r,?r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))] + "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)" + "* + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) + && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xffff); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } + if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])) + { + output_asm_insn (AS2 (xor%L0,%0,%0),operands); + output_asm_insn (AS2 (mov%W0,%1,%w0),operands); + RET; + } + + if (TARGET_ZERO_EXTEND_WITH_AND) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xffff); + if (i386_aligned_p (operands[1])) + output_asm_insn (AS2 (mov%L0,%k1,%k0),operands); + else + output_asm_insn (AS2 (mov%W0,%1,%w0),operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } + +#ifdef INTEL_SYNTAX + return AS2 (movzx,%1,%0); +#else + return AS2 (movz%W0%L0,%1,%0); +#endif +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));") + + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 65535)))] + "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO" + + "* return AS2 (movz%B0%W0,%1,%0);") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=q,&q,?r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))] + "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)" + "* + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) + && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } + if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0])) + { + if(!reg_overlap_mentioned_p(operands[0],operands[1])) + { + output_asm_insn (AS2 (xor%L0,%k0,%k0), operands); + output_asm_insn (AS2 (mov%B0,%1,%b0), operands); + } + else + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (mov%B0,%1,%b0),operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + } + RET; + } + +#ifdef INTEL_SYNTAX + return AS2 (movzx,%1,%0); +#else + return AS2 (movz%B0%W0,%1,%0); +#endif +}") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:HI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "register_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (and:HI (match_dup 0) + (const_int 255)))] + "if (GET_CODE (operands[1]) == SUBREG && SUBREG_WORD (operands[1]) == 0) + operands[1] = SUBREG_REG (operands[1]); + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG + || REGNO (operands[0]) == REGNO (operands[1])) + FAIL; + operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO" + "* return AS2 (movz%B0%L0,%1,%0);") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=q,&q,?r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))] + "! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)" + "* + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) + && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } + if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0])) + { + if(!reg_overlap_mentioned_p (operands[0], operands[1])) + { + output_asm_insn (AS2 (xor%L0,%0,%0),operands); + output_asm_insn (AS2 (mov%B0,%1,%b0),operands); + } + else + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (mov%B0,%1,%b0), operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + } + RET; + } + + if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + operands[1] = gen_rtx_REG (SImode, REGNO (operands[1])); + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } + +#ifdef INTEL_SYNTAX + return AS2 (movzx,%1,%0); +#else + return AS2 (movz%B0%L0,%1,%0); +#endif +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "register_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND + && ! reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));") + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o") + (zero_extend:DI (match_operand:SI 1 "general_operand" "0,rm,r")))] + "" + "#") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:SI 1 "register_operand" "")))] + "reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" + [(set (match_dup 4) (const_int 0))] + "split_di (&operands[0], 1, &operands[3], &operands[4]);") + +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (zero_extend:DI (match_operand:SI 1 "general_operand" "")))] + "reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 4) (const_int 0))] + "split_di (&operands[0], 1, &operands[3], &operands[4]);") + +;;- sign extension instructions + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=A,?r,?Ar,*o") + (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,*r"))) + (clobber (match_scratch:SI 2 "=X,X,X,&r"))] + "" + "#") + +;; Extend to memory case when source register does die. +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (match_operand:SI 2 "register_operand" ""))] + "(flow2_completed + && dead_or_set_p (insn, operands[1]) + && !reg_mentioned_p (operands[1], operands[0]))" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31))) + (set (match_dup 4) (match_dup 1))] + "split_di (&operands[0], 1, &operands[3], &operands[4]);") + +;; Extend to memory case when source register does not die. +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (match_operand:SI 2 "register_operand" ""))] + "flow2_completed" + [(const_int 0)] + " +{ + split_di (&operands[0], 1, &operands[3], &operands[4]); + + emit_move_insn (operands[3], operands[1]); + + /* Generate a cltd if possible and doing so it profitable. */ + if (true_regnum (operands[1]) == 0 + && true_regnum (operands[2]) == 1 + && (optimize_size || !TARGET_PENTIUM)) + { + emit_insn (gen_ashrsi3_31 (operands[2], operands[1])); + } + else + { + emit_move_insn (operands[2], operands[1]); + emit_insn (gen_ashrsi3_31 (operands[2], operands[2])); + } + emit_move_insn (operands[4], operands[2]); + DONE; +}") + +;; Extend to register case. Optimize case where source and destination +;; registers match and cases where we can use cltd. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (match_scratch:SI 2 ""))] + "reload_completed" + [(const_int 0)] + " +{ + split_di (&operands[0], 1, &operands[3], &operands[4]); + + if (true_regnum (operands[3]) != true_regnum (operands[1])) + emit_move_insn (operands[3], operands[1]); + + /* Generate a cltd if possible and doing so it profitable. */ + if (true_regnum (operands[3]) == 0 + && (optimize_size || !TARGET_PENTIUM)) + { + emit_insn (gen_ashrsi3_31 (operands[4], operands[3])); + DONE; + } + + if (true_regnum (operands[4]) != true_regnum (operands[1])) + emit_move_insn (operands[4], operands[1]); + + emit_insn (gen_ashrsi3_31 (operands[4], operands[4])); + DONE; +}") + +;; Note that the i386 programmers' manual says that the opcodes +;; are named movsx..., but the assembler on Unix does not accept that. +;; We use what the Unix assembler expects. + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "" + "* +{ + if (REGNO (operands[0]) == 0 + && REG_P (operands[1]) && REGNO (operands[1]) == 0 + && (optimize_size || ix86_cpu != PROCESSOR_K6)) +#ifdef INTEL_SYNTAX + return \"cwde\"; +#else + return \"cwtl\"; +#endif + +#ifdef INTEL_SYNTAX + return AS2 (movsx,%1,%0); +#else + return AS2 (movs%W0%L0,%1,%0); +#endif +}") + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "" + "* +{ + if (REGNO (operands[0]) == 0 + && REG_P (operands[1]) && REGNO (operands[1]) == 0 + && (optimize_size || ix86_cpu != PROCESSOR_K6)) + return \"cbtw\"; + +#ifdef INTEL_SYNTAX + return AS2 (movsx,%1,%0); +#else + return AS2 (movs%B0%W0,%1,%0); +#endif +}") + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "" + "* +{ +#ifdef INTEL_SYNTAX + return AS2 (movsx,%1,%0); +#else + return AS2 (movs%B0%L0,%1,%0); +#endif +}") + + +;; Truncation of long long -> 32 bit + +(define_expand "truncdisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + rtx target = gen_reg_rtx (SImode); + emit_insn (gen_truncdisi2 (target, operands[1])); + emit_move_insn (operands[0], target); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx low[2], high[2], xops[2]; + + split_di (&operands[1], 1, low, high); + xops[0] = operands[0]; + xops[1] = low[0]; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + RET; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32))))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx low[2], high[2], xops[2]; + + split_di (&operands[1], 1, low, high); + xops[0] = operands[0]; + xops[1] = high[0]; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + RET; +}") + + + +;; Conversions between float and double. + +(define_expand "extendsfdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3))])] + "TARGET_80387" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); + + operands[2] = assign_386_stack_local (SFmode, 0); + operands[3] = assign_386_stack_local (DFmode, 0); +}") + +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!f,!*r") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f"))) + (clobber (match_operand:SF 2 "memory_operand" "m,m,m,m")) + (clobber (match_operand:DF 3 "memory_operand" "m,m,m,o"))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop,fld,fpop")]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float_extend:DF (match_operand:SF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:DF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float_extend:DF (match_dup 2)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float_extend:DF (match_operand:SF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:DF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])" + [(set (match_dup 3) + (float_extend:DF (match_dup 1))) + (set (match_dup 0) + (match_dup 3))] + "") + +(define_split + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:DF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_extend:DF (match_dup 1)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop")]) + +(define_expand "extenddfxf2" + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (float_extend:XF + (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3))])] + "TARGET_80387" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); + + operands[2] = assign_386_stack_local (DFmode, 0); + operands[3] = assign_386_stack_local (XFmode, 0); +}") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r") + (float_extend:XF + (match_operand:DF 1 "nonimmediate_operand" "fm,f,*r,f"))) + (clobber (match_operand:DF 2 "memory_operand" "m,m,o,m")) + (clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop,fld,fpop")]) + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float_extend:XF (match_operand:DF 1 "register_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float_extend:XF (match_dup 2)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float_extend:XF (match_operand:DF 1 "register_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])" + [(set (match_dup 3) + (float_extend:XF (match_dup 1))) + (set (match_dup 0) + (match_dup 3))] + "") + +(define_split + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_extend:XF (match_dup 1)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m") + (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop")]) + +(define_expand "extendsfxf2" + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (float_extend:XF + (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3))])] + "TARGET_80387" + " +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); + + operands[2] = assign_386_stack_local (SFmode, 0); + operands[3] = assign_386_stack_local (XFmode, 0); +}") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r") + (float_extend:XF + (match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f"))) + (clobber (match_operand:SF 2 "memory_operand" "m,m,m,m")) + (clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop,fld,fpop")]) + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float_extend:XF (match_operand:SF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float_extend:XF (match_dup 2)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float_extend:XF (match_operand:SF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])" + [(set (match_dup 3) + (float_extend:XF (match_dup 1))) + (set (match_dup 0) + (match_dup 3))] + "") + +(define_split + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" "")) + (clobber (match_operand:XF 3 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_extend:XF (match_dup 1)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m") + (float_extend:XF + (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "TARGET_80387 && (GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != MEM)" + "* +{ + output_float_extend (insn, operands); + return \"\"; +}" + [(set_attr "type" "fld,fpop")]) + +(define_expand "truncdfsf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (float_truncate:SF + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (SFmode, 0); +}") + +(define_insn "" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "0,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + rtx xops[1]; + + xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2]; + + if (stack_top_dies || STACK_REG_P (operands[0])) + output_asm_insn (AS1 (fstp%z0,%0), xops); + else + output_asm_insn (AS1 (fst%z0,%0), xops); + + if (STACK_REG_P (operands[0])) + return AS1 (fld%z2,%2); + else if (NON_STACK_REG_P (operands[0])) + return AS2 (mov%L0,%2,%0); + + return \"\"; +}" + [(set_attr "type" "fpop")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float_truncate:SF (match_operand:DF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (float_truncate:SF (match_dup 1))) + (set (match_dup 0) + (match_dup 2))] + "") + +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (float_truncate:SF (match_operand:DF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_truncate:SF (match_dup 1)))] + "") + +;; This cannot output into an f-reg because there is no way to be sure +;; of truncating in that case. + +(define_insn "" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (stack_top_dies) + return AS1 (fstp%z0,%0); + else + return AS1 (fst%z0,%0); +}" + [(set_attr "type" "fpop")]) + +(define_expand "truncxfsf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (float_truncate:SF + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (SFmode, 0); +}") + +(define_insn "" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r") + (float_truncate:SF + (match_operand:XF 1 "register_operand" "0,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + rtx xops[1]; + + xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2]; + + if (stack_top_dies || STACK_REG_P (operands[0])) + output_asm_insn (AS1 (fstp%z0,%0), xops); + else + output_asm_insn (AS1 (fst%z0,%0), xops); + + if (STACK_REG_P (operands[0])) + return AS1 (fld%z2,%2); + else if (NON_STACK_REG_P (operands[0])) + return AS2 (mov%L0,%2,%0); + + return \"\"; +}" + [(set_attr "type" "fpop")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (float_truncate:SF (match_dup 1))) + (set (match_dup 0) + (match_dup 2))] + "") + +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) + (clobber (match_operand:SF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_truncate:SF (match_dup 1)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF (match_operand:XF 1 "register_operand" "f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (stack_top_dies) + return AS1 (fstp%z0,%0); + else + return AS1 (fst%z0,%0); +}" + [(set_attr "type" "fpop")]) + +(define_expand "truncxfdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (float_truncate:DF + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (DFmode, 0); +}") + +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r") + (float_truncate:DF + (match_operand:XF 1 "register_operand" "0,f,f"))) + (clobber (match_operand:DF 2 "memory_operand" "m,m,o"))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + rtx xops[2]; + + xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2]; + + if (stack_top_dies || STACK_REG_P (operands[0])) + output_asm_insn (AS1 (fstp%z0,%0), xops); + else + output_asm_insn (AS1 (fst%z0,%0), xops); + + if (STACK_REG_P (operands[0])) + return AS1 (fld%z2,%2); + else if (NON_STACK_REG_P (operands[0])) + { + xops[0] = operands[0]; + xops[1] = operands[2]; + output_asm_insn (output_move_double (xops), xops); + } + + return \"\"; +}" + [(set_attr "type" "fpop")]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (float_truncate:DF (match_dup 1))) + (set (match_dup 0) + (match_dup 2))] + "") + +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float_truncate:DF (match_dup 1)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "memory_operand" "=m") + (float_truncate:DF (match_operand:XF 1 "register_operand" "f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (stack_top_dies) + return AS1 (fstp%z0,%0); + else + return AS1 (fst%z0,%0); +}" + [(set_attr "type" "fpop")]) + +;; Conversions between floating point and fix point. + +(define_expand "fix_truncsfsi2" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "")))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (SImode, 0); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!r") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f,f")))) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:SI 4 "memory_operand" "m,m")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +(define_expand "fix_truncsfdi2" + [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "")))) + (clobber (match_dup 1)) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[1] = copy_to_mode_reg (SFmode, operands[1]); + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (DImode, 0); +}") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!r") + (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f,f")))) + (clobber (match_dup 1)) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:DI 4 "memory_operand" "m,o")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +(define_expand "fix_truncdfsi2" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "")))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (SImode, 0); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!r") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f,f")))) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:SI 4 "memory_operand" "m,m")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +(define_expand "fix_truncdfdi2" + [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "")))) + (clobber (match_dup 1)) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[1] = copy_to_mode_reg (DFmode, operands[1]); + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (DImode, 0); +}") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!r") + (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f,f")))) + (clobber (match_dup 1)) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:DI 4 "memory_operand" "m,o")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +(define_expand "fix_truncxfsi2" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "")))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (SImode, 0); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,!r") + (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f,f")))) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:SI 4 "memory_operand" "m,m")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +(define_expand "fix_truncxfdi2" + [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "")))) + (clobber (match_dup 1)) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:HI 5 ""))])] + "TARGET_80387" + " +{ + operands[1] = copy_to_mode_reg (XFmode, operands[1]); + operands[2] = (rtx) assign_386_stack_local (HImode, 0); + operands[3] = (rtx) assign_386_stack_local (HImode, 1); + operands[4] = (rtx) assign_386_stack_local (DImode, 0); +}") + +(define_insn "" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,!r") + (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f,f")))) + (clobber (match_dup 1)) + (clobber (match_operand:HI 2 "memory_operand" "m,m")) + (clobber (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:DI 4 "memory_operand" "m,o")) + (clobber (match_scratch:HI 5 "=&r,&r"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fpop")]) + +;; Conversion between fixed point and floating point. + +;; ??? Possibly represent floatunssidf2 here in gcc2. + +(define_expand "floatsisf2" + [(parallel [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:SI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (SImode, 0);") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:SI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:SI 1 "memory_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:SF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:SI 1 "register_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:SF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floathisf2" + [(parallel [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (HImode, 0);") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:HI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:HI 1 "memory_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:SF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:HI 1 "register_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:SF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floatdisf2" + [(parallel [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (DImode, 0);") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:DI 2 "memory_operand" "m,o"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "memory_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:SF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "register_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:SF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:DI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floatsidf2" + [(parallel [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:SI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (SImode, 0);") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:SI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:SI 1 "memory_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:DF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:SI 1 "register_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:DF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floathidf2" + [(parallel [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (HImode, 0);") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:HI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:HI 1 "memory_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:DF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:HI 1 "register_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:DF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floatdidf2" + [(parallel [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:DI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (DImode, 0);") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:DI 2 "memory_operand" "m,o"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:DI 1 "memory_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:DF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (float:DF (match_operand:DI 1 "register_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:DF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:DI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floatsixf2" + [(parallel [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:SI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (SImode, 0);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:SI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:SI 1 "memory_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:XF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:SI 1 "register_operand" ""))) + (clobber (match_operand:SI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:XF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (float:XF (match_operand:SI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floathixf2" + [(parallel [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (HImode, 0);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:HI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:HI 2 "memory_operand" "m,m"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:HI 1 "memory_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:XF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:HI 1 "register_operand" ""))) + (clobber (match_operand:HI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:XF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (float:XF (match_operand:HI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +(define_expand "floatdixf2" + [(parallel [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:DI 1 "nonimmediate_operand" ""))) + (clobber (match_dup 2))])] + "TARGET_80387" + "operands[2] = assign_386_stack_local (DImode, 0);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,!r"))) + (clobber (match_operand:DI 2 "memory_operand" "m,o"))] + "TARGET_80387" + "#") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:DI 1 "memory_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 0) + (float:XF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:DI 1 "register_operand" ""))) + (clobber (match_operand:DI 2 "memory_operand" ""))] + "TARGET_80387 && reload_completed" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (float:XF (match_dup 2)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (float:XF (match_operand:DI 1 "memory_operand" "m")))] + "TARGET_80387" + "* return AS1 (fild%z1,%1);" + [(set_attr "type" "fpop")]) + +;;- add instructions + +(define_insn "*addsidi3_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,!&r,!r,o,!o") + (plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o") + (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri")))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7]; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (add%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (adc%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + output_asm_insn (AS2 (add%L0,%2,%0), low); + output_asm_insn (AS2 (adc%L0,%2,%0), high); + cc_status.value1 = high[0]; + cc_status.flags = CC_NO_OVERFLOW; + RET; +}" + [(set_attr "type" "binary")]) + +(define_insn "addsidi3_2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,!&r,&r,o,o,!o") + (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,o,ri,ri,i,r")) + (match_operand:DI 1 "general_operand" "0,0,0,iF,ro,roiF,riF,o,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,X,&r,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7]; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + { + if (rtx_equal_p (low[0], operands[2])) + { + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (add%L0,%1,%0), low); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + RET; + } + if (rtx_equal_p (high[0], operands[2])) + { + if (GET_CODE (operands[0]) != MEM) + { + output_asm_insn (AS2 (mov%L0,%2,%0), low); + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (add%L0,%1,%0), low); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + } + else + { + /* It's too late to ask for a scratch now - but this + will probably not happen too often. */ + output_asm_insn (AS2 (add%L1,%2,%1), low); + output_asm_insn (AS2 (mov%L0,%1,%0), low); + output_asm_insn (AS2 (mov%L1,%2,%1), low); + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + output_asm_insn (AS2 (sub%L1,%0,%1), low); + output_asm_insn (AS1 (neg%L1,%1), low); + } + RET; + } + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (add%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (adc%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + output_asm_insn (AS2 (add%L0,%2,%0), low); + output_asm_insn (AS2 (adc%L0,%2,%0), high); + cc_status.value1 = high[0]; + cc_status.flags = CC_NO_OVERFLOW; + RET; +}" + [(set_attr "type" "binary")]) + +(define_insn "adddi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7], temp; + + CC_STATUS_INIT; + + if (rtx_equal_p (operands[0], operands[2])) + { + temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } + + split_di (operands, 3, low, high); + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (add%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (adc%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + cc_status.value1 = high[0]; + cc_status.flags = CC_NO_OVERFLOW; + + if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[2]; + xops[3] = low[2]; + xops[4] = operands[3]; + + output_asm_insn (AS2 (mov%L4,%3,%4), xops); + output_asm_insn (AS2 (add%L1,%4,%1), xops); + output_asm_insn (AS2 (mov%L4,%2,%4), xops); + output_asm_insn (AS2 (adc%L0,%4,%0), xops); + } + + else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) + { + output_asm_insn (AS2 (add%L0,%2,%0), low); + output_asm_insn (AS2 (adc%L0,%2,%0), high); + } + + else + output_asm_insn (AS2 (add%L0,%2,%0), high); + + RET; +}" + [(set_attr "type" "binary")]) + +;; On a 486, it is faster to do movl/addl than to do a single leal if +;; operands[1] and operands[2] are both registers. + +(define_expand "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r") + (match_operand:SI 2 "general_operand" "rmi,ri,ri")))] + "ix86_binary_operator_ok (PLUS, SImode, operands)" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && (REG_P (operands[2]) || CONSTANT_P (operands[2])) + && REGNO (operands[0]) != REGNO (operands[1])) + { + if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) + return AS2 (add%L0,%1,%0); + + if (operands[2] == stack_pointer_rtx) + { + rtx temp; + + temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } + + if (operands[2] != stack_pointer_rtx) + { + CC_STATUS_INIT; + operands[1] = SET_SRC (PATTERN (insn)); + return AS2 (lea%L0,%a1,%0); + } + } + + if (!rtx_equal_p (operands[0], operands[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + + if (operands[2] == const1_rtx) + return AS1 (inc%L0,%0); + + if (operands[2] == constm1_rtx) + return AS1 (dec%L0,%0); + + /* subl $-128,%ebx is smaller than addl $128,%ebx. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 128) + { + /* This doesn't compute the carry bit in the same way + * as add%L0, but we use inc and dec above and they + * don't set the carry bit at all. If inc/dec don't need + * a CC_STATUS_INIT, this doesn't either... */ + operands[2] = GEN_INT (-128); + return AS2 (sub%L0,%2,%0); + } + + return AS2 (add%L0,%2,%0); +}" + [(set_attr "type" "binary")]) + +;; addsi3 is faster, so put this after. + +(define_insn "movsi_lea" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + /* Adding a constant to a register is faster with an add. */ + /* ??? can this ever happen? */ + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && rtx_equal_p (operands[0], XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 1); + + if (operands[1] == const1_rtx) + return AS1 (inc%L0,%0); + + if (operands[1] == constm1_rtx) + return AS1 (dec%L0,%0); + + return AS2 (add%L0,%1,%0); + } + + CC_STATUS_INIT; + return AS2 (lea%L0,%a1,%0); +}" + [(set_attr "type" "lea")]) + +;; ??? `lea' here, for three operand add? If leaw is used, only %bx, +;; %si and %di can appear in SET_SRC, and output_asm_insn might not be +;; able to handle the operand. But leal always works? + +(define_expand "addhi3" + [(set (match_operand:HI 0 "general_operand" "") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,?r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r") + (match_operand:HI 2 "general_operand" "ri,rm,ri")))] + "ix86_binary_operator_ok (PLUS, HImode, operands)" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && (REG_P (operands[2]) || CONSTANT_P (operands[2])) + && REGNO (operands[0]) != REGNO (operands[1])) + { + if (operands[2] == stack_pointer_rtx) + abort (); + + CC_STATUS_INIT; + operands[1] + = gen_rtx_PLUS (SImode, + gen_rtx_REG (SImode, REGNO (operands[1])), + (! REG_P (operands[2]) + ? operands[2] + : gen_rtx_REG (SImode, REGNO (operands[2])))); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + return AS2 (lea%L0,%a1,%0); + } + + /* ??? what about offsettable memory references? */ + if (!TARGET_PENTIUMPRO /* partial stalls are just too painful to risk. */ + && QI_REG_P (operands[0]) + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 0xff) == 0 + && i386_cc_probably_useless_p (insn)) + { + int byteval = (INTVAL (operands[2]) >> 8) & 0xff; + CC_STATUS_INIT; + + if (byteval == 1) + return AS1 (inc%B0,%h0); + else if (byteval == 255) + return AS1 (dec%B0,%h0); + + operands[2] = GEN_INT (byteval); + return AS2 (add%B0,%2,%h0); + } + + /* Use a 32-bit operation when possible, to avoid the prefix penalty. */ + if (REG_P (operands[0]) + && i386_aligned_p (operands[2]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + + if (GET_CODE (operands[2]) == CONST_INT) + { + HOST_WIDE_INT intval = 0xffff & INTVAL (operands[2]); + + if (intval == 1) + return AS1 (inc%L0,%k0); + + if (intval == 0xffff) + return AS1 (dec%L0,%k0); + + operands[2] = i386_sext16_if_const (operands[2]); + } + return AS2 (add%L0,%k2,%k0); + } + + if (operands[2] == const1_rtx) + return AS1 (inc%W0,%0); + + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return AS1 (dec%W0,%0); + + return AS2 (add%W0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_expand "addqi3" + [(set (match_operand:QI 0 "general_operand" "") + (plus:QI (match_operand:QI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,?q") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,q") + (match_operand:QI 2 "general_operand" "qn,qmn,qn")))] + "ix86_binary_operator_ok (PLUS, QImode, operands)" + "* +{ + if (REG_P (operands[0]) && REG_P (operands[1]) + && (REG_P (operands[2]) || CONSTANT_P (operands[2])) + && (REGNO (operands[0]) != REGNO (operands[1]) + || NON_QI_REG_P (operands[1]) + || (REG_P (operands[2]) && NON_QI_REG_P (operands[2])))) + { + if (operands[2] == stack_pointer_rtx) + abort (); + + CC_STATUS_INIT; + operands[1] + = gen_rtx_PLUS (SImode, + gen_rtx_REG (SImode, REGNO (operands[1])), + (! REG_P (operands[2]) + ? operands[2] + : gen_rtx_REG (SImode, REGNO (operands[2])))); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + return AS2 (lea%L0,%a1,%0); + } + if (operands[2] == const1_rtx) + return AS1 (inc%B0,%0); + + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return AS1 (dec%B0,%0); + + return AS2 (add%B0,%2,%0); +}" + [(set_attr "type" "binary")]) + +;Lennart Augustsson <augustss@cs.chalmers.se> +;says this pattern just makes slower code: +; pushl %ebp +; addl $-80,(%esp) +;instead of +; leal -80(%ebp),%eax +; pushl %eax +; +;(define_insn "" +; [(set (match_operand:SI 0 "push_operand" "=<") +; (plus:SI (match_operand:SI 1 "register_operand" "%r") +; (match_operand:SI 2 "nonmemory_operand" "ri")))] +; "" +; "* +;{ +; rtx xops[4]; +; xops[0] = operands[0]; +; xops[1] = operands[1]; +; xops[2] = operands[2]; +; xops[3] = gen_rtx_MEM (SImode, stack_pointer_rtx); +; output_asm_insn (\"push%z1 %1\", xops); +; output_asm_insn (AS2 (add%z3,%2,%3), xops); +; RET; +;}") + +;; The patterns that match these are at the end of this file. + +(define_expand "addxf3" + [(set (match_operand:XF 0 "register_operand" "") + (plus:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] + "TARGET_80387" + "") + +(define_expand "adddf3" + [(set (match_operand:DF 0 "register_operand" "") + (plus:DF (match_operand:DF 1 "nonimmediate_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +(define_expand "addsf3" + [(set (match_operand:SF 0 "register_operand" "") + (plus:SF (match_operand:SF 1 "nonimmediate_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +;;- subtract instructions + +(define_insn "subsidi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,&r,!&r,o,o,!o") + (minus:DI (match_operand:DI 1 "general_operand" "0iF,0,roiF,roiF,riF,o,o") + (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,i,r")))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,&r,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7]; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (sub%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (sbb%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + output_asm_insn (AS2 (sub%L0,%2,%0), low); + output_asm_insn (AS2 (sbb%L0,%2,%0), high); + cc_status.value1 = high[0]; + cc_status.flags = CC_NO_OVERFLOW; + + RET; +}" + [(set_attr "type" "binary")]) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,o,o,!&r,!o") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,0iF,or,roiF,roiF") + (match_operand:DI 2 "general_operand" "or,riF,or,iF,roiF,roiF"))) + (clobber (match_scratch:SI 3 "=X,X,&r,&r,X,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7]; + + CC_STATUS_INIT; + + split_di (operands, 3, low, high); + + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (sub%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (sbb%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + cc_status.value1 = high[0]; + cc_status.flags = CC_NO_OVERFLOW; + + if (GET_CODE (operands[3]) == REG) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[2]; + xops[3] = low[2]; + xops[4] = operands[3]; + + output_asm_insn (AS2 (mov%L4,%3,%4), xops); + output_asm_insn (AS2 (sub%L1,%4,%1), xops); + output_asm_insn (AS2 (mov%L4,%2,%4), xops); + output_asm_insn (AS2 (sbb%L0,%4,%0), xops); + } + + else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) + { + output_asm_insn (AS2 (sub%L0,%2,%0), low); + output_asm_insn (AS2 (sbb%L0,%2,%0), high); + } + + else + output_asm_insn (AS2 (sub%L0,%2,%0), high); + + + RET; +}" + [(set_attr "type" "binary")]) + +(define_expand "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "ix86_binary_operator_ok (MINUS, SImode, operands)" + "* return AS2 (sub%L0,%2,%0);" + [(set_attr "type" "binary")]) + +(define_expand "subhi3" + [(set (match_operand:HI 0 "general_operand" "") + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "ix86_binary_operator_ok (MINUS, HImode, operands)" + "* +{ + if (REG_P (operands[0]) + && i386_aligned_p (operands[2]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (sub%L0,%k2,%k0); + } + return AS2 (sub%W0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_expand "subqi3" + [(set (match_operand:QI 0 "general_operand" "") + (minus:QI (match_operand:QI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "ix86_binary_operator_ok (MINUS, QImode, operands)" + "* return AS2 (sub%B0,%2,%0);" + [(set_attr "type" "binary")]) + +;; The patterns that match these are at the end of this file. + +(define_expand "subxf3" + [(set (match_operand:XF 0 "register_operand" "") + (minus:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] + "TARGET_80387" + "") + +(define_expand "subdf3" + [(set (match_operand:DF 0 "register_operand" "") + (minus:DF (match_operand:DF 1 "nonimmediate_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +(define_expand "subsf3" + [(set (match_operand:SF 0 "register_operand" "") + (minus:SF (match_operand:SF 1 "nonimmediate_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +;;- multiply instructions + +;(define_insn "mulqi3" +; [(set (match_operand:QI 0 "register_operand" "=a") +; (mult:QI (match_operand:QI 1 "register_operand" "%0") +; (match_operand:QI 2 "nonimmediate_operand" "qm")))] +; "" +; "imul%B0 %2,%0") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm") + (match_operand:HI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%W0,%2,%0); + return AS3 (imul%W0,%2,%1,%0); +}" + [(set_attr "type" "imul")]) + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm") + (match_operand:SI 2 "general_operand" "g,i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == REG + && REGNO (operands[1]) == REGNO (operands[0]) + && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG)) + /* Assembler has weird restrictions. */ + return AS2 (imul%L0,%2,%0); + return AS3 (imul%L0,%2,%1,%0); +}" + [(set_attr "type" "imul")]) + +(define_insn "umulqihi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0")) + (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] + "" + "mul%B0 %2" + [(set_attr "type" "imul")]) + +(define_insn "mulqihi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0")) + (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] + "" + "imul%B0 %2" + [(set_attr "type" "imul")]) + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=A") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))] + "TARGET_WIDE_MULTIPLY" + "mul%L0 %2" + [(set_attr "type" "imul")]) + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=A") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))] + "TARGET_WIDE_MULTIPLY" + "imul%L0 %2" + [(set_attr "type" "imul")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a")) + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_WIDE_MULTIPLY" + "mul%L0 %2" + [(set_attr "type" "imul")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%a")) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_WIDE_MULTIPLY" + "imul%L0 %2" + [(set_attr "type" "imul")]) + +;; The patterns that match these are at the end of this file. + +(define_expand "mulxf3" + [(set (match_operand:XF 0 "register_operand" "") + (mult:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] + "TARGET_80387" + "") + +(define_expand "muldf3" + [(set (match_operand:DF 0 "register_operand" "") + (mult:DF (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +(define_expand "mulsf3" + [(set (match_operand:SF 0 "register_operand" "") + (mult:SF (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +;;- divide instructions + +(define_insn "divqi3" + [(set (match_operand:QI 0 "register_operand" "=a") + (div:QI (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")))] + "" + "idiv%B0 %2") + +(define_insn "udivqi3" + [(set (match_operand:QI 0 "register_operand" "=a") + (udiv:QI (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")))] + "" + "div%B0 %2" + [(set_attr "type" "idiv")]) + +;; The patterns that match these are at the end of this file. + +(define_expand "divxf3" + [(set (match_operand:XF 0 "register_operand" "") + (div:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] + "TARGET_80387" + "") + +(define_expand "divdf3" + [(set (match_operand:DF 0 "register_operand" "") + (div:DF (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +(define_expand "divsf3" + [(set (match_operand:SF 0 "register_operand" "") + (div:SF (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +;; Remainder instructions. + +(define_insn "divmodsi4" + [(set (match_operand:SI 0 "register_operand" "=a") + (div:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:SI 3 "register_operand" "=&d") + (mod:SI (match_dup 1) (match_dup 2)))] + "" + "* +{ +#ifdef INTEL_SYNTAX + output_asm_insn (\"cdq\", operands); +#else + output_asm_insn (\"cltd\", operands); +#endif + return AS1 (idiv%L0,%2); +}" + [(set_attr "type" "idiv")]) + +(define_insn "divmodhi4" + [(set (match_operand:HI 0 "register_operand" "=a") + (div:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:HI 3 "register_operand" "=&d") + (mod:HI (match_dup 1) (match_dup 2)))] + "" + "cwtd\;idiv%W0 %2" + [(set_attr "type" "idiv")]) + +;; ??? Can we make gcc zero extend operand[0]? +(define_insn "udivmodsi4" + [(set (match_operand:SI 0 "register_operand" "=a") + (udiv:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:SI 3 "register_operand" "=&d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "* +{ + output_asm_insn (AS2 (xor%L3,%3,%3), operands); + return AS1 (div%L0,%2); +}" + [(set_attr "type" "idiv")]) + +;; ??? Can we make gcc zero extend operand[0]? +(define_insn "udivmodhi4" + [(set (match_operand:HI 0 "register_operand" "=a") + (udiv:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:HI 3 "register_operand" "=&d") + (umod:HI (match_dup 1) (match_dup 2)))] + "" + "* +{ + output_asm_insn (AS2 (xor%W0,%3,%3), operands); + return AS1 (div%W0,%2); +}" + [(set_attr "type" "idiv")]) + +/* +;;this should be a valid double division which we may want to add + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=a") + (udiv:DI (match_operand:DI 1 "register_operand" "a") + (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:SI 3 "register_operand" "=d") + (umod:SI (match_dup 1) (match_dup 2)))] + "" + "div%L0 %2,%0" + [(set_attr "type" "idiv")]) +*/ + +;;- and instructions + +;; On i386, +;; movzbl %bl,%ebx +;; is faster than +;; andl $255,%ebx +;; +;; but if the reg is %eax, then the "andl" is faster. +;; +;; On i486, the "andl" is always faster than the "movzbl". +;; +;; On both i386 and i486, a three operand AND is as fast with movzbl or +;; movzwl as with andl, if operands[0] != operands[1]. + +;; The `r' in `rm' for operand 3 looks redundant, but it causes +;; optional reloads to be generated if op 3 is a pseudo in a stack slot. + +(define_insn "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "* +{ + HOST_WIDE_INT intval; + if (!rtx_equal_p (operands[0], operands[1]) + && rtx_equal_p (operands[0], operands[2])) + { + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } + switch (GET_CODE (operands[2])) + { + case CONST_INT: + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + intval = INTVAL (operands[2]); + /* zero-extend 16->32? */ + if (intval == 0xffff && REG_P (operands[0]) + && (! REG_P (operands[1]) + || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) + && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1]))) + { + /* ??? tege: Should forget CC_STATUS only if we clobber a + remembered operand. Fix that later. */ + CC_STATUS_INIT; +#ifdef INTEL_SYNTAX + return AS2 (movzx,%w1,%0); +#else + return AS2 (movz%W0%L0,%w1,%0); +#endif + } + + /* zero extend 8->32? */ + if (intval == 0xff && REG_P (operands[0]) + && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1])) + && (! REG_P (operands[1]) + || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) + && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1]))) + { + /* ??? tege: Should forget CC_STATUS only if we clobber a + remembered operand. Fix that later. */ + CC_STATUS_INIT; +#ifdef INTEL_SYNTAX + return AS2 (movzx,%b1,%0); +#else + return AS2 (movz%B0%L0,%b1,%0); +#endif + } + + /* Check partial bytes.. non-QI-regs are not available */ + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; + + /* only low byte has zero bits? */ + if (~(intval | 0xff) == 0) + { + intval &= 0xff; + if (REG_P (operands[0])) + { + if (intval == 0) + { + CC_STATUS_INIT; + return AS2 (xor%B0,%b0,%b0); + } + + /* we're better off with the 32-bit version if reg != EAX */ + /* the value is sign-extended in 8 bits */ + if (REGNO (operands[0]) != 0 && (intval & 0x80)) + break; + } + + CC_STATUS_INIT; + + operands[2] = GEN_INT (intval); + + if (intval == 0) + return AS2 (mov%B0,%2,%b0); + + return AS2 (and%B0,%2,%b0); + } + + /* only second byte has zero? */ + if (~(intval | 0xff00) == 0) + { + CC_STATUS_INIT; + + intval = (intval >> 8) & 0xff; + operands[2] = GEN_INT (intval); + if (intval == 0) + { + if (REG_P (operands[0])) + return AS2 (xor%B0,%h0,%h0); + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (mov%B0,%2,%b0); + } + + if (REG_P (operands[0])) + return AS2 (and%B0,%2,%h0); + + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (and%B0,%2,%b0); + } + + if (REG_P (operands[0])) + break; + + /* third byte has zero bits? */ + if (~(intval | 0xff0000) == 0) + { + intval = (intval >> 16) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 2); +byte_and_operation: + CC_STATUS_INIT; + operands[2] = GEN_INT (intval); + if (intval == 0) + return AS2 (mov%B0,%2,%b0); + return AS2 (and%B0,%2,%b0); + } + + /* fourth byte has zero bits? */ + if (~(intval | 0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_and_operation; + } + + /* Low word is zero? */ + if (intval == 0xffff0000) + { +word_zero_and_operation: + CC_STATUS_INIT; + operands[2] = const0_rtx; + return AS2 (mov%W0,%2,%w0); + } + + /* High word is zero? */ + if (intval == 0x0000ffff) + { + operands[0] = adj_offsettable_operand (operands[0], 2); + goto word_zero_and_operation; + } + + default: + break; + } + + return AS2 (and%L0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + { + /* Can we ignore the upper byte? */ + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) + && (INTVAL (operands[2]) & 0xff00) == 0xff00) + { + CC_STATUS_INIT; + + if ((INTVAL (operands[2]) & 0xff) == 0) + { + operands[2] = const0_rtx; + return AS2 (mov%B0,%2,%b0); + } + + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); + return AS2 (and%B0,%2,%b0); + } + + /* Can we ignore the lower byte? */ + /* ??? what about offsettable memory references? */ + if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & 0xff) == 0xff) + { + CC_STATUS_INIT; + + if ((INTVAL (operands[2]) & 0xff00) == 0) + { + operands[2] = const0_rtx; + return AS2 (mov%B0,%2,%h0); + } + + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); + return AS2 (and%B0,%2,%h0); + } + + /* use 32-bit ops on registers when there are no sign issues.. */ + if (REG_P (operands[0])) + { + if (!(INTVAL (operands[2]) & ~0x7fff)) + return AS2 (and%L0,%2,%k0); + } + } + + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + /* If op[2] is constant, we should zero-extend it and */ + /* make a note that op[0] has been zero-extended, so */ + /* that we could use 32-bit ops on it forthwith, but */ + /* there is no such reg-note available. Instead we do */ + /* a sign extension as that can result in shorter asm */ + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (and%L0,%k2,%k0); + } + + /* Use a 32-bit word with the upper bits set, invalidate CC */ + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + HOST_WIDE_INT val = INTVAL (operands[2]); + CC_STATUS_INIT; + val |= ~0xffff; + if (val != INTVAL (operands[2])) + operands[2] = GEN_INT (val); + return AS2 (and%L0,%k2,%k0); + } + + return AS2 (and%W0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "* return AS2 (and%B0,%2,%0);" + [(set_attr "type" "binary")]) + +/* I am nervous about these two.. add them later.. +;I presume this means that we have something in say op0= eax which is small +;and we want to and it with memory so we can do this by just an +;andb m,%al and have success. +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=r") + (and:SI (zero_extend:SI + (match_operand:HI 1 "nonimmediate_operand" "rm")) + (match_operand:SI 2 "general_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" + "and%W0 %1,%0") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=q") + (and:SI + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")) + (match_operand:SI 2 "register_operand" "0")))] + "GET_CODE (operands[2]) == CONST_INT + && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" + "and%L0 %1,%0") + +*/ + +;;- Bit set (inclusive or) instructions + +;; This optimizes known byte-wide operations to memory, and in some cases +;; to QI registers.. Note that we don't want to use the QI registers too +;; aggressively, because often the 32-bit register instruction is the same +;; size, and likely to be faster on PentiumPro. +(define_insn "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "* +{ + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) + { + case CONST_INT: + + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; + + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = INTVAL (operands[2]); + if ((intval & ~0xff) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_or_operation: + CC_STATUS_INIT; + + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + + if (intval == 0xff) + return AS2 (mov%B0,%2,%b0); + + return AS2 (or%B0,%2,%b0); + } + + /* second byte? */ + if ((intval & ~0xff00) == 0) + { + intval >>= 8; + + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + operands[2] = GEN_INT (intval); + if (intval == 0xff) + return AS2 (mov%B0,%2,%h0); + + return AS2 (or%B0,%2,%h0); + } + + operands[0] = adj_offsettable_operand (operands[0], 1); + goto byte_or_operation; + } + + if (REG_P (operands[0])) + break; + + /* third byte? */ + if ((intval & ~0xff0000) == 0) + { + intval >>= 16; + operands[0] = adj_offsettable_operand (operands[0], 2); + goto byte_or_operation; + } + + /* fourth byte? */ + if ((intval & ~0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_or_operation; + } + + default: + break; + } + + return AS2 (or%L0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "* +{ + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) + { + case CONST_INT: + + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; + + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = 0xffff & INTVAL (operands[2]); + + if ((intval & 0xff00) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_or_operation: + CC_STATUS_INIT; + + if (intval == 0xff) + return AS2 (mov%B0,%2,%b0); + + return AS2 (or%B0,%2,%b0); + } + + /* high byte? */ + if ((intval & 0xff) == 0) + { + intval >>= 8; + operands[2] = GEN_INT (intval); + + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + if (intval == 0xff) + return AS2 (mov%B0,%2,%h0); + + return AS2 (or%B0,%2,%h0); + } + + operands[0] = adj_offsettable_operand (operands[0], 1); + + goto byte_or_operation; + } + + default: + break; + } + + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (or%L0,%k2,%k0); + } + + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + CC_STATUS_INIT; + intval = 0xffff & INTVAL (operands[2]); + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (or%L0,%2,%k0); + } + + return AS2 (or%W0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "" + "* return AS2 (or%B0,%2,%0);" + [(set_attr "type" "binary")]) + +;;- xor instructions + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "" + "* +{ + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) + { + case CONST_INT: + + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; + + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = INTVAL (operands[2]); + if ((intval & ~0xff) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_xor_operation: + CC_STATUS_INIT; + + if (intval == 0xff + && (!TARGET_PENTIUM || optimize_size + || (GET_CODE (operands[0]) == MEM + && memory_address_info (XEXP (operands[0], 0), 1)))) + return AS1 (not%B0,%b0); + + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (xor%B0,%2,%b0); + } + + /* second byte? */ + if ((intval & ~0xff00) == 0) + { + intval >>= 8; + + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + if (intval == 0xff + && (!TARGET_PENTIUM || optimize_size + || (GET_CODE (operands[0]) == MEM + && memory_address_info (XEXP (operands[0], 0), 1)))) + return AS1 (not%B0,%h0); + + operands[2] = GEN_INT (intval); + return AS2 (xor%B0,%2,%h0); + } + + operands[0] = adj_offsettable_operand (operands[0], 1); + + goto byte_xor_operation; + } + + if (REG_P (operands[0])) + break; + + /* third byte? */ + if ((intval & ~0xff0000) == 0) + { + intval >>= 16; + operands[0] = adj_offsettable_operand (operands[0], 2); + goto byte_xor_operation; + } + + /* fourth byte? */ + if ((intval & ~0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_xor_operation; + } + + default: + break; + } + + return AS2 (xor%L0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "" + "* +{ + if (GET_CODE (operands[2]) == CONST_INT + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + { + /* Can we ignore the upper byte? */ + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) + && (INTVAL (operands[2]) & 0xff00) == 0) + { + CC_STATUS_INIT; + if (INTVAL (operands[2]) & 0xffff0000) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); + + if (INTVAL (operands[2]) == 0xff + && (!TARGET_PENTIUM || optimize_size + || (GET_CODE (operands[0]) == MEM + && memory_address_info (XEXP (operands[0], 0), 1)))) + return AS1 (not%B0,%b0); + + return AS2 (xor%B0,%2,%b0); + } + + /* Can we ignore the lower byte? */ + /* ??? what about offsettable memory references? */ + if (QI_REG_P (operands[0]) + && (INTVAL (operands[2]) & 0xff) == 0) + { + CC_STATUS_INIT; + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); + + if (INTVAL (operands[2]) == 0xff + && (!TARGET_PENTIUM || optimize_size + || (GET_CODE (operands[0]) == MEM + && memory_address_info (XEXP (operands[0], 0), 1)))) + return AS1 (not%B0,%h0); + + return AS2 (xor%B0,%2,%h0); + } + } + + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (xor%L0,%k2,%k0); + } + + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + HOST_WIDE_INT intval; + CC_STATUS_INIT; + intval = 0xffff & INTVAL (operands[2]); + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (xor%L0,%2,%k0); + } + + return AS2 (xor%W0,%2,%0); +}" + [(set_attr "type" "binary")]) + +(define_insn "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qm")))] + "" + "* return AS2 (xor%B0,%2,%0);" + [(set_attr "type" "binary")]) + +;; logical operations for DImode + +(define_insn "anddi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro") + (and:DI (match_operand:DI 1 "general_operand" "%0,0") + (match_operand:DI 2 "general_operand" "oriF,riF")))] + "" + "#" + [(set_attr "type" "binary")]) + + +(define_insn "iordi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro") + (ior:DI (match_operand:DI 1 "general_operand" "%0,0") + (match_operand:DI 2 "general_operand" "oriF,riF")))] + "" + "#" + [(set_attr "type" "binary")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro") + (xor:DI (match_operand:DI 1 "general_operand" "%0,0") + (match_operand:DI 2 "general_operand" "oriF,riF")))] + "" + "#" + [(set_attr "type" "binary")]) + +(define_split + [(set (match_operand:DI 0 "general_operand" "") + (match_operator:DI 3 "ix86_logical_operator" + [(match_operand:DI 1 "general_operand" "") + (match_operand:DI 2 "general_operand" "")]))] + "" + [(set (match_dup 4) (match_op_dup:SI 3 [(match_dup 6) (match_dup 8)])) + (set (match_dup 5) (match_op_dup:SI 3 [(match_dup 7) (match_dup 9)]))] + "split_di (&operands[0], 1, &operands[4], &operands[5]); + split_di (&operands[1], 1, &operands[6], &operands[7]); + split_di (&operands[2], 1, &operands[8], &operands[9]);") + +;;- negation instructions + +(define_insn "negdi2" + [(set (match_operand:DI 0 "general_operand" "=&ro") + (neg:DI (match_operand:DI 1 "general_operand" "0")))] + "" + "* +{ + rtx xops[2], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = const0_rtx; + xops[1] = high[0]; + + output_asm_insn (AS1 (neg%L0,%0), low); + output_asm_insn (AS2 (adc%L1,%0,%1), xops); + output_asm_insn (AS1 (neg%L0,%0), high); + RET; +}") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] + "" + "neg%L0 %0") + +(define_insn "neghi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] + "" + "* + if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS1(neg%L0,%k0); + } + return AS1(neg%W0,%0);") + +(define_insn "negqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))] + "" + "neg%B0 %0") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fpop")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fpop")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fpop")]) + +(define_insn "negxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (match_operand:XF 1 "register_operand" "0")))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fpop")]) + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fpop")]) + +;; Absolute value instructions + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fpop")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fpop")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fpop")]) + +(define_insn "absxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (abs:XF (match_operand:XF 1 "register_operand" "0")))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fpop")]) + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fpop")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt") + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " + "fsqrt") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (float_extend:DF + (match_operand:SF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt") + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " + "fsqrt") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt") + +(define_insn "sindf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fsin") + +(define_insn "sinsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fsin") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(float_extend:DF + (match_operand:SF 1 "register_operand" "0"))] 1))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fsin") + +(define_insn "sinxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fsin") + +(define_insn "cosdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fcos") + +(define_insn "cossf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fcos") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(float_extend:DF + (match_operand:SF 1 "register_operand" "0"))] 2))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fcos") + +(define_insn "cosxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" + "fcos") + +;;- one complement instructions + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] + "" + "* +{ + /* A Pentium NOT is not pariable. Output it only in case of complex + memory address, because XOR will be inpariable anyway because + of immediate/displacement rule. */ + + if (TARGET_PENTIUM && !optimize_size + && (GET_CODE (operands[0]) != MEM + || memory_address_info (XEXP (operands[0], 0), 1) == 0)) + { + rtx xops[2]; + xops[0] = operands[0]; + xops[1] = GEN_INT (0xffffffff); + output_asm_insn (AS2 (xor%L0,%1,%0), xops); + RET; + } + else + return AS1 (not%L0,%0); +}") + +(define_insn "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] + "" + "* +{ + /* A Pentium NOT is not pariable. Output it only in case of complex + memory address, because XOR will be inpariable anyway because + of immediate/displacement rule. */ + + if (TARGET_PENTIUM && !optimize_size + && (GET_CODE (operands[0]) != MEM + || memory_address_info (XEXP (operands[0], 0), 1) == 0)) + { + rtx xops[2]; + xops[0] = operands[0]; + xops[1] = GEN_INT (0xffff); + if (REG_P (operands[0]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + output_asm_insn (AS2 (xor%L0,%1,%k0), xops); + } + else + output_asm_insn (AS2 (xor%W0,%1,%0), xops); + RET; + } + else + { + if (REG_P (operands[0]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + return AS1 (not%L0,%k0); + } + return AS1 (not%W0,%0); + } +}") + +(define_insn "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))] + "" + "* +{ + /* A Pentium NOT is not pariable. Output it only in case of complex + memory address, because XOR will be inpariable anyway because + of immediate/displacement rule. */ + + if (TARGET_PENTIUM && !optimize_size + && (GET_CODE (operands[0]) != MEM + || memory_address_info (XEXP (operands[0], 0), 1) == 0)) + { + rtx xops[2]; + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (xor%B0,%1,%0), xops); + RET; + } + else + return AS1 (not%B0,%0); +}") + +;;- arithmetic shift instructions + +;; DImode shifts are implemented using the i386 "shift double" opcode, +;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count +;; is variable, then the count is in %cl and the "imm" operand is dropped +;; from the assembler input. + +;; This instruction shifts the target reg/mem as usual, but instead of +;; shifting in zeros, bits are shifted in from reg operand. If the insn +;; is a left shift double, bits are taken from the high order bits of +;; reg, else if the insn is a shift right double, bits are taken from the +;; low order bits of reg. So if %eax is "1234" and %edx is "5678", +;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345". + +;; Since sh[lr]d does not change the `reg' operand, that is done +;; separately, making all shifts emit pairs of shift double and normal +;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to +;; support a 63 bit shift, each shift where the count is in a reg expands +;; to a pair of shifts, a branch, a shift by 32 and a label. + +;; If the shift count is a constant, we need never emit more than one +;; shift pair, instead using moves and sign extension for counts greater +;; than 31. + +(define_expand "ashldi3" + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(define_insn "ashldi3_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "J")))] + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" + "* +{ + rtx xops[4], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + xops[2] = low[0]; + xops[3] = high[0]; + + if (INTVAL (xops[0]) > 31) + { + output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops); + output_asm_insn (AS2 (sal%L2,%0,%2), xops); + } + RET; +}") + +(define_insn "ashldi3_non_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "c")))] + "" + "* +{ + rtx xops[5], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = GEN_INT (32); + xops[2] = low[0]; + xops[3] = high[0]; + xops[4] = gen_label_rtx (); + + output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops); + output_asm_insn (AS2 (sal%L2,%0,%2), xops); + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); + RET; +}") + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))] + "" + "") + +(define_expand "ashlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "nonmemory_operand" "")))] + "" + "") + +(define_expand "ashlqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "") + +;; Pattern for shifts which can be encoded into an lea instruction. +;; This is kept as a separate pattern so that regmove can optimize cases +;; where we know the source and destination must match. +;; +;; Do not expose this pattern when optimizing for size since we never want +;; to use lea when optimizing for size since mov+sal is smaller than lea. + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r") + (match_operand:SI 2 "small_shift_operand" "M,M")))] + "! optimize_size" + "* return output_ashl (insn, operands);") + +;; Generic left shift pattern to catch all cases not handled by the +;; shift pattern above. +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "cI")))] + "" + "* return output_ashl (insn, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r") + (match_operand:HI 2 "small_shift_operand" "M,M")))] + "! optimize_size" + "* return output_ashl (insn, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "nonmemory_operand" "cI")))] + "" + "* return output_ashl (insn, operands);") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,q") + (match_operand:QI 2 "small_shift_operand" "M,M")))] + "! optimize_size" + "* return output_ashl (insn, operands);") + +;; Generic left shift pattern to catch all cases not handled by the +;; shift pattern above. +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))] + "" + "* return output_ashl (insn, operands);") + +;; See comment above `ashldi3' about how this works. + +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_ashrdi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_ashrdi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(define_insn "ashldi3_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32)))] + "" + "* +{ + rtx low[2], high[2], xops[4]; + + split_di (operands, 2, low, high); + xops[0] = high[0]; + xops[1] = low[1]; + xops[2] = low[0]; + xops[3] = const0_rtx; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + if (GET_CODE (low[0]) == MEM) + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + else + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + RET; +}") + +(define_insn "ashrdi3_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "J")))] + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" + "* +{ + rtx xops[4], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + xops[2] = low[0]; + xops[3] = high[0]; + + if (INTVAL (xops[0]) > 31) + { + xops[1] = GEN_INT (31); + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */ + + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); + output_asm_insn (AS2 (sar%L3,%0,%3), xops); + } + + RET; +}") + +(define_insn "ashrdi3_non_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "c")))] + "" + "* +{ + rtx xops[5], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = GEN_INT (32); + xops[2] = low[0]; + xops[3] = high[0]; + xops[4] = gen_label_rtx (); + + output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); + output_asm_insn (AS2 (sar%L3,%0,%3), xops); + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + xops[1] = GEN_INT (31); + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); + RET; +}") + +(define_insn "ashrsi3_31" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,d") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,a") + (const_int 31)))] + "!TARGET_PENTIUM || optimize_size" + "@ + sar%L0 $31,%0 + cltd") + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%L0,%b2,%0); + else + return AS2 (sar%L0,%2,%0); +}") + +(define_insn "ashrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%W0,%b2,%0); + else + return AS2 (sar%W0,%2,%0); +}") + +(define_insn "ashrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (sar%B0,%b2,%0); + else + return AS2 (sar%B0,%2,%0); +}") + +;;- logical shift instructions + +;; See comment above `ashldi3' about how this works. + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(define_insn "lshrdi3_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32)))] + "" + "* +{ + rtx low[2], high[2], xops[4]; + + split_di (operands, 2, low, high); + xops[0] = low[0]; + xops[1] = high[1]; + xops[2] = high[0]; + xops[3] = const0_rtx; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + if (GET_CODE (low[0]) == MEM) + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + else + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + RET; +}") + +(define_insn "lshrdi3_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "J")))] + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" + "* +{ + rtx xops[4], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + xops[2] = low[0]; + xops[3] = high[0]; + + if (INTVAL (xops[0]) > 31) + { + output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L3,%3,%3), xops); + + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (shr%L2,%0,%2), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); + output_asm_insn (AS2 (shr%L3,%0,%3), xops); + } + + RET; +}") + +(define_insn "lshrdi3_non_const_int" + [(set (match_operand:DI 0 "register_operand" "=&r") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" "c")))] + "" + "* +{ + rtx xops[5], low[1], high[1]; + + CC_STATUS_INIT; + + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = GEN_INT (32); + xops[2] = low[0]; + xops[3] = high[0]; + xops[4] = gen_label_rtx (); + + output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); + output_asm_insn (AS2 (shr%L3,%0,%3), xops); + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L3,%3,%3), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); + RET; +}") + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%L0,%b2,%0); + else + return AS2 (shr%L0,%2,%1); +}") + +(define_insn "lshrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%W0,%b2,%0); + else + return AS2 (shr%W0,%2,%0); +}") + +(define_insn "lshrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (shr%B0,%b2,%0); + else + return AS2 (shr%B0,%2,%0); +}") + +;;- rotate instructions + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%L0,%b2,%0); + else + return AS2 (rol%L0,%2,%0); +}") + +(define_insn "rotlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%W0,%b2,%0); + else + return AS2 (rol%W0,%2,%0); +}") + +(define_insn "rotlqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (rol%B0,%b2,%0); + else + return AS2 (rol%B0,%2,%0); +}") + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%L0,%b2,%0); + else + return AS2 (ror%L0,%2,%0); +}") + +(define_insn "rotrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%W0,%b2,%0); + else + return AS2 (ror%W0,%2,%0); +}") + +(define_insn "rotrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))] + "" + "* +{ + if (REG_P (operands[2])) + return AS2 (ror%B0,%b2,%0); + else + return AS2 (ror%B0,%2,%0); +}") + +/* +;; This usually looses. But try a define_expand to recognize a few case +;; we can do efficiently, such as accessing the "high" QImode registers, +;; %ah, %bh, %ch, %dh. +;; ??? Note this has a botch on the mode of operand 0, which needs to be +;; fixed if this is ever enabled. +(define_insn "insv" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r") + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "nonmemory_operand" "ri"))] + "" + "* +{ + if (INTVAL (operands[1]) + INTVAL (operands[2]) > GET_MODE_BITSIZE (SImode)) + abort (); + if (GET_CODE (operands[3]) == CONST_INT) + { + unsigned int mask = (1 << INTVAL (operands[1])) - 1; + operands[1] = GEN_INT (~(mask << INTVAL (operands[2]))); + output_asm_insn (AS2 (and%L0,%1,%0), operands); + operands[3] = GEN_INT (INTVAL (operands[3]) << INTVAL (operands[2])); + output_asm_insn (AS2 (or%L0,%3,%0), operands); + } + else + { + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + if (INTVAL (operands[2])) + output_asm_insn (AS2 (ror%L0,%2,%0), operands); + output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands); + operands[2] = GEN_INT (BITS_PER_WORD + - INTVAL (operands[1]) - INTVAL (operands[2])); + if (INTVAL (operands[2])) + output_asm_insn (AS2 (ror%L0,%2,%0), operands); + } + RET; +}") +*/ +/* +;; ??? There are problems with the mode of operand[3]. The point of this +;; is to represent an HImode move to a "high byte" register. + +(define_expand "insv" + [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "")) + (match_operand:QI 3 "nonmemory_operand" "ri"))] + "" + " +{ + if (GET_CODE (operands[1]) != CONST_INT + || GET_CODE (operands[2]) != CONST_INT) + FAIL; + + if (! (INTVAL (operands[1]) == 8 + && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0)) + && ! INTVAL (operands[1]) == 1) + FAIL; +}") +*/ + +;; On i386, the register count for a bit operation is *not* truncated, +;; so SHIFT_COUNT_TRUNCATED must not be defined. + +;; On i486, the shift & or/and code is faster than bts or btr. If +;; operands[0] is a MEM, the bt[sr] is half as fast as the normal code. + +;; On i386, bts is a little faster if operands[0] is a reg, and a +;; little slower if operands[0] is a MEM, than the shift & or/and code. +;; Use bts & btr, since they reload better. + +;; General bit set and clear. +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm") + (const_int 1) + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "const_int_operand" "n"))] + "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT" + "* +{ + CC_STATUS_INIT; + + if (INTVAL (operands[3]) == 1) + return AS2 (bts%L0,%2,%0); + else + return AS2 (btr%L0,%2,%0); +}") + +;; Bit complement. See comments on previous pattern. +;; ??? Is this really worthwhile? +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (xor:SI (ashift:SI (const_int 1) + (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "nonimmediate_operand" "0")))] + "TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT" + "* +{ + CC_STATUS_INIT; + + return AS2 (btc%L0,%1,%0); +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "register_operand" "r"))))] + "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT" + "* +{ + CC_STATUS_INIT; + + return AS2 (btc%L0,%2,%0); +}") + +;; Recognizers for bit-test instructions. + +;; The bt opcode allows a MEM in operands[0]. But on both i386 and +;; i486, it is faster to copy a MEM to REG and then use bt, than to use +;; bt on the MEM directly. + +;; ??? The first argument of a zero_extract must not be reloaded, so +;; don't allow a MEM in the operand predicate without allowing it in the +;; constraint. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") + (const_int 1) + (match_operand:SI 1 "register_operand" "r")))] + "GET_CODE (operands[1]) != CONST_INT" + "* +{ + cc_status.flags |= CC_Z_IN_NOT_C; + return AS2 (bt%L0,%1,%0); +}") + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")))] + "" + "* +{ + unsigned int mask; + + mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]); + operands[1] = GEN_INT (mask); + + if (QI_REG_P (operands[0]) + /* A Pentium test is pairable only with eax. Not with ah or al. */ + && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM + || optimize_size)) + { + if ((mask & ~0xff) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } + + if ((mask & ~0xff00) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 8); + return AS2 (test%B0,%1,%h0); + } + } + + return AS2 (test%L0,%1,%0); +}") + +;; ??? All bets are off if operand 0 is a volatile MEM reference. +;; The CPU may access unspecified bytes around the actual target byte. + +(define_insn "" + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")))] + "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])" + "* +{ + unsigned int mask; + + mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]); + operands[1] = GEN_INT (mask); + + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) + /* A Pentium test is pairable only with eax. Not with ah or al. */ + && (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM + || optimize_size)) + { + if ((mask & ~0xff) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } + + if ((mask & ~0xff00) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 8); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } + } + + if (GET_CODE (operands[0]) == MEM && (mask & ~0xff0000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 16); + operands[0] = adj_offsettable_operand (operands[0], 2); + return AS2 (test%B0,%1,%b0); + } + + if (GET_CODE (operands[0]) == MEM && (mask & ~0xff000000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 24); + operands[0] = adj_offsettable_operand (operands[0], 3); + return AS2 (test%B0,%1,%b0); + } + } + + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%L0,%1,%0); + + return AS2 (test%L1,%0,%1); +}") + +;; Store-flag instructions. + +;; For all sCOND expanders, also expand the compare or test insn that +;; generates cc0. Generate an equality comparison if `seq' or `sne'. + +(define_expand "seq" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (eq:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + +(define_expand "sne" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (ne:QI (cc0) (const_int 0)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + +(define_expand "sgt" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (gt:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sgtu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (gtu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "slt" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (lt:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sltu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (ltu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sge" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (ge:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sgeu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (geu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sle" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (le:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "sleu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (leu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +;; The 386 sCOND opcodes can write to memory. But a gcc sCOND insn may +;; not have any input reloads. A MEM write might need an input reload +;; for the address of the MEM. So don't allow MEM as the SET_DEST. + +(define_insn "*setcc" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (match_operator:QI 1 "comparison_operator" [(cc0) (const_int 0)]))] + "reload_completed || register_operand (operands[0], QImode)" + "* +{ + enum rtx_code code = GET_CODE (operands[1]); + if (cc_prev_status.flags & CC_TEST_AX) + { + int eq; + HOST_WIDE_INT c; + operands[2] = gen_rtx_REG (SImode, 0); + switch (code) + { + case EQ: + c = 0x4000; + eq = 0; + break; + case NE: + c = 0x4000; + eq = 1; + break; + case GT: + c = 0x4100; + eq = 1; + break; + case LT: + c = 0x100; + eq = 0; + break; + case GE: + c = 0x100; + eq = 1; + break; + case LE: + c = 0x4100; + eq = 0; + break; + default: + abort (); + } + if (!TARGET_PENTIUM || optimize_size) + { + operands[3] = GEN_INT (c >> 8); + output_asm_insn (AS2 (test%B0,%3,%h2), operands); + } + else + { + operands[3] = GEN_INT (c); + output_asm_insn (AS2 (test%L0,%3,%2), operands); + } + return eq ? AS1 (sete,%0) : AS1 (setne, %0); + } + + if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT)) + return (char *)0; + return AS1(set%D1,%0); +}") + + +;; Basic conditional jump instructions. +;; We ignore the overflow flag for signed branch instructions. + +;; For all bCOND expanders, also expand the compare or test insn that +;; generates cc0. Generate an equality comparison if `beq' or `bne'. + +(define_expand "beq" + [(match_dup 1) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + +(define_expand "bne" + [(match_dup 1) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + + +(define_expand "bgt" + [(match_dup 1) + (set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "bgtu" + [(match_dup 1) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "blt" + [(match_dup 1) + (set (pc) + (if_then_else (lt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + + +(define_expand "bltu" + [(match_dup 1) + (set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "bge" + [(match_dup 1) + (set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "bgeu" + [(match_dup 1) + (set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "ble" + [(match_dup 1) + (set (pc) + (if_then_else (le (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_expand "bleu" + [(match_dup 1) + (set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "* +{ + enum rtx_code code = GET_CODE (operands[0]); + if (cc_prev_status.flags & CC_TEST_AX) + { + int eq; + HOST_WIDE_INT c; + operands[2] = gen_rtx_REG (SImode, 0); + switch (code) + { + case EQ: + c = 0x4000; + eq = 0; + break; + case NE: + c = 0x4000; + eq = 1; + break; + case GT: + c = 0x4100; + eq = 1; + break; + case LT: + c = 0x100; + eq = 0; + break; + case GE: + c = 0x100; + eq = 1; + break; + case LE: + c = 0x4100; + eq = 0; + break; + default: + abort (); + } + if (!TARGET_PENTIUM || optimize_size) + { + operands[3] = GEN_INT (c >> 8); + output_asm_insn (AS2 (test%B0,%3,%h2), operands); + } + else + { + operands[3] = GEN_INT (c); + output_asm_insn (AS2 (test%L0,%3,%2), operands); + } + return eq ? AS1 (je,%l1) : AS1 (jne, %l1); + } + if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT)) + return (char *)0; + + return AS1(j%D0,%l1); +}") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "* +{ + enum rtx_code code = GET_CODE (operands[0]); + if (cc_prev_status.flags & CC_TEST_AX) + { + int eq; + HOST_WIDE_INT c; + operands[2] = gen_rtx_REG (SImode, 0); + switch (code) + { + case EQ: + c = 0x4000; + eq = 1; + break; + case NE: + c = 0x4000; + eq = 0; + break; + case GT: + c = 0x4100; + eq = 0; + break; + case LT: + c = 0x100; + eq = 1; + break; + case GE: + c = 0x100; + eq = 0; + break; + case LE: + c = 0x4100; + eq = 1; + break; + default: + abort (); + } + if (!TARGET_PENTIUM || optimize_size) + { + operands[3] = GEN_INT (c >> 8); + output_asm_insn (AS2 (test%B0,%3,%h2), operands); + } + else + { + operands[3] = GEN_INT (c); + output_asm_insn (AS2 (test%L0,%3,%2), operands); + } + return eq ? AS1 (je,%l1) : AS1 (jne, %l1); + } + if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT)) + return (char *)0; + + return AS1(j%d0,%l1); +}") + +;; Unconditional and other jump instructions + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "jmp %l0" + [(set_attr "memory" "none")]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "" + "* +{ + CC_STATUS_INIT; + + return AS1 (jmp,%*%0); +}" + [(set_attr "memory" "none")]) + +;; ??? could transform while(--i > 0) S; to if (--i > 0) do S; while(--i); +;; if S does not change i + +(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 (match_operator 0 "arithmetic_comparison_operator" + [(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+c*r,m") + (match_operand:SI 2 "general_operand" "rmi,ri")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "* +{ + CC_STATUS_INIT; + + if (GET_CODE (operands[1]) == REG && REGNO (operands[2]) == 2 && + operands[2] == constm1_rtx && ix86_cpu == PROCESSOR_K6) + return \"loop %l3\"; + + if (operands[2] == constm1_rtx) + output_asm_insn (AS1 (dec%L1,%1), operands); + + else if (operands[2] == const1_rtx) + output_asm_insn (AS1 (inc%L1,%1), operands); + + else + output_asm_insn (AS2 (add%L1,%2,%1), operands); + + return AS1 (%J0,%l3); +}") + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "arithmetic_comparison_operator" + [(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m") + (match_operand:SI 2 "general_operand" "rmi,ri")) + (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc))) + (set (match_dup 1) + (minus:SI (match_dup 1) + (match_dup 2)))] + "" + "* +{ + CC_STATUS_INIT; + if (operands[2] == const1_rtx) + output_asm_insn (AS1 (dec%L1,%1), operands); + + else if (operands[1] == constm1_rtx) + output_asm_insn (AS1 (inc%L1,%1), operands); + + else + output_asm_insn (AS2 (sub%L1,%2,%1), operands); + + return AS1 (%J0,%l3); +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = const1_rtx; + output_asm_insn (AS2 (sub%L0,%2,%0), operands); + return \"jnc %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = const1_rtx; + output_asm_insn (AS2 (sub%L0,%2,%0), operands); + return \"jc %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (dec%L0,%0), operands); + return \"jnz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (dec%L0,%0), operands); + return \"jz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (inc%L0,%0), operands); + return \"jnz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (inc%L0,%0), operands); + return \"jz %l1\"; +}") + +;; Implement switch statements when generating PIC code. Switches are +;; implemented by `tablejump' when not using -fpic. + +;; Emit code here to do the range checking and make the index zero based. + +(define_expand "casesi" + [(set (match_dup 5) + (match_operand:SI 0 "general_operand" "")) + (set (match_dup 6) + (minus:SI (match_dup 5) + (match_operand:SI 1 "general_operand" ""))) + (set (cc0) + (compare:CC (match_dup 6) + (match_operand:SI 2 "general_operand" ""))) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 4 "" "")) + (pc))) + (parallel + [(set (pc) + (minus:SI (reg:SI 3) + (mem:SI (plus:SI (mult:SI (match_dup 6) + (const_int 4)) + (label_ref (match_operand 3 "" "")))))) + (clobber (match_scratch:SI 7 ""))])] + "flag_pic" + " +{ + operands[5] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); + current_function_uses_pic_offset_table = 1; +}") + +;; Implement a casesi insn. + +;; Each entry in the "addr_diff_vec" looks like this as the result of the +;; two rules below: +;; +;; .long _GLOBAL_OFFSET_TABLE_+[.-.L2] +;; +;; 1. An expression involving an external reference may only use the +;; addition operator, and only with an assembly-time constant. +;; The example above satisfies this because ".-.L2" is a constant. +;; +;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is +;; given the value of "GOT - .", where GOT is the actual address of +;; the Global Offset Table. Therefore, the .long above actually +;; stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2". The +;; expression "GOT - .L2" by itself would generate an error from as(1). +;; +;; The pattern below emits code that looks like this: +;; +;; movl %ebx,reg +;; subl TABLE@GOTOFF(%ebx,index,4),reg +;; jmp reg +;; +;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since +;; the addr_diff_vec is known to be part of this module. +;; +;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which +;; evaluates to just ".L2". + +(define_insn "" + [(set (pc) + (minus:SI (reg:SI 3) + (mem:SI (plus:SI + (mult:SI (match_operand:SI 0 "register_operand" "r") + (const_int 4)) + (label_ref (match_operand 1 "" "")))))) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "* +{ + rtx xops[4]; + + xops[0] = operands[0]; + xops[1] = operands[1]; + xops[2] = operands[2]; + xops[3] = pic_offset_table_rtx; + + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops); + output_asm_insn (AS1 (jmp,%*%2), xops); + ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps); + RET; +}") + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))] + "" + "* +{ + CC_STATUS_INIT; + + return AS1 (jmp,%*%0); +}") + +;; Call insns. + +;; If generating PIC code, the predicate indirect_operand will fail +;; for operands[0] containing symbolic references on all of the named +;; call* patterns. Each named pattern is followed by an unnamed pattern +;; that matches any call to a symbolic CONST (ie, a symbol_ref). The +;; unnamed patterns are only used while generating PIC code, because +;; otherwise the named patterns match. + +;; Call subroutine returning no value. + +(define_expand "call_pop" + [(parallel [(call (match_operand:QI 0 "indirect_operand" "") + (match_operand:SI 1 "general_operand" "")) + (set (reg:SI 7) + (plus:SI (reg:SI 7) + (match_operand:SI 3 "immediate_operand" "")))])] + "" + " +{ + rtx addr; + + if (operands[3] == const0_rtx) + { + emit_insn (gen_call (operands[0], operands[1])); + DONE; + } + + if (flag_pic) + current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[0], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[0], 0) = force_reg (Pmode, addr); + + if (! expander_call_insn_operand (operands[0], QImode)) + operands[0] + = change_address (operands[0], VOIDmode, + copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); +}") + +(define_insn "" + [(call (match_operand:QI 0 "call_insn_operand" "m") + (match_operand:SI 1 "general_operand" "g")) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 3 "immediate_operand" "i")))] + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + operands[0] = XEXP (operands[0], 0); + return AS1 (call,%*%0); + } + else + return AS1 (call,%P0); +}") + +(define_insn "" + [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) + (match_operand:SI 1 "general_operand" "g")) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 3 "immediate_operand" "i")))] + "!HALF_PIC_P ()" + "call %P0") + +(define_expand "call" + [(call (match_operand:QI 0 "indirect_operand" "") + (match_operand:SI 1 "general_operand" ""))] + ;; Operand 1 not used on the i386. + "" + " +{ + rtx addr; + + if (flag_pic) + current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[0], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[0], 0) = force_reg (Pmode, addr); + + if (! expander_call_insn_operand (operands[0], QImode)) + operands[0] + = change_address (operands[0], VOIDmode, + copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); +}") + +(define_insn "" + [(call (match_operand:QI 0 "call_insn_operand" "m") + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not used on the i386. + "" + "* +{ + if (GET_CODE (operands[0]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + { + operands[0] = XEXP (operands[0], 0); + return AS1 (call,%*%0); + } + else + return AS1 (call,%P0); +}") + +(define_insn "" + [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) + (match_operand:SI 1 "general_operand" "g"))] + ;; Operand 1 not used on the i386. + "!HALF_PIC_P ()" + "call %P0") + +;; Call subroutine, returning value in operand 0 +;; (which must be a hard register). + +(define_expand "call_value_pop" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "indirect_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (set (reg:SI 7) + (plus:SI (reg:SI 7) + (match_operand:SI 4 "immediate_operand" "")))])] + "" + " +{ + rtx addr; + + if (operands[4] == const0_rtx) + { + emit_insn (gen_call_value (operands[0], operands[1], operands[2])); + DONE; + } + + if (flag_pic) + current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[1], 0) = force_reg (Pmode, addr); + + if (! expander_call_insn_operand (operands[1], QImode)) + operands[1] + = change_address (operands[1], VOIDmode, + copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "call_insn_operand" "m") + (match_operand:SI 2 "general_operand" "g"))) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 4 "immediate_operand" "i")))] + "" + "* +{ + if (GET_CODE (operands[1]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 0); + output_asm_insn (AS1 (call,%*%1), operands); + } + else + output_asm_insn (AS1 (call,%P1), operands); + + RET; +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) + (match_operand:SI 2 "general_operand" "g"))) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 4 "immediate_operand" "i")))] + "!HALF_PIC_P ()" + "call %P1") + +(define_expand "call_value" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "indirect_operand" "") + (match_operand:SI 2 "general_operand" "")))] + ;; Operand 2 not used on the i386. + "" + " +{ + rtx addr; + + if (flag_pic) + current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[1], 0) = force_reg (Pmode, addr); + + if (! expander_call_insn_operand (operands[1], QImode)) + operands[1] + = change_address (operands[1], VOIDmode, + copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (match_operand:QI 1 "call_insn_operand" "m") + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not used on the i386. + "" + "* +{ + if (GET_CODE (operands[1]) == MEM + && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 0); + output_asm_insn (AS1 (call,%*%1), operands); + } + else + output_asm_insn (AS1 (call,%P1), operands); + + RET; +}") + +(define_insn "" + [(set (match_operand 0 "" "=rf") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) + (match_operand:SI 2 "general_operand" "g")))] + ;; Operand 2 not used on the i386. + "!HALF_PIC_P ()" + "call %P1") + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" + " +{ + int i; + + /* In order to give reg-stack an easier job in validating two + coprocessor registers as containing a possible return value, + simply pretend the untyped call returns a complex long double + value. */ + + emit_call_insn (TARGET_80387 + ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG), + operands[0], const0_rtx) + : gen_call (operands[0], 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)] + "" + "" + [(set_attr "memory" "none")]) + +;; Insn emitted into the body of a function to return from a function. +;; This is only done if the function's epilogue is known to be simple. +;; See comments for simple_386_epilogue in i386.c. + +(define_expand "return" + [(return)] + "ix86_can_use_return_insn_p ()" + "") + +(define_insn "return_internal" + [(return)] + "reload_completed" + "ret" + [(set_attr "memory" "none")]) + +(define_insn "return_pop_internal" + [(return) + (use (match_operand:SI 0 "const_int_operand" ""))] + "reload_completed" + "ret %0" + [(set_attr "memory" "none")]) + +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "memory" "none")]) + +(define_expand "prologue" + [(const_int 1)] + "" + " +{ + ix86_expand_prologue (); + DONE; +}") + +;; The use of UNSPEC here is currently not necessary - a simple SET of ebp +;; to itself would be enough. But this way we are safe even if some optimizer +;; becomes too clever in the future. +(define_insn "prologue_set_stack_ptr" + [(set (reg:SI 7) + (minus:SI (reg:SI 7) (match_operand:SI 0 "immediate_operand" "i"))) + (set (reg:SI 6) (unspec:SI [(reg:SI 6)] 4))] + "" + "* +{ + rtx xops [2]; + + xops[0] = operands[0]; + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (sub%L1,%0,%1), xops); + RET; +}" + [(set_attr "memory" "none")]) + +(define_insn "prologue_set_got" + [(set (match_operand:SI 0 "" "") + (unspec_volatile + [(plus:SI (match_dup 0) + (plus:SI (match_operand:SI 1 "symbolic_operand" "") + (minus:SI (pc) (match_operand 2 "" ""))))] 1))] + "" + "* +{ + char buffer[64]; + + if (TARGET_DEEP_BRANCH_PREDICTION) + { + sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0)); + output_asm_insn (buffer, operands); + } + else + { + sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0)); + output_asm_insn (buffer, operands); + } + RET; +}") + +(define_insn "prologue_get_pc" + [(set (match_operand:SI 0 "" "") + (unspec_volatile [(plus:SI (pc) (match_operand 1 "" ""))] 2))] + "" + "* +{ + output_asm_insn (AS1 (call,%X1), operands); + if (! TARGET_DEEP_BRANCH_PREDICTION) + { + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1])); + } + RET; +}" + [(set_attr "memory" "none")]) + +(define_insn "prologue_get_pc_and_set_got" + [(unspec_volatile [(match_operand:SI 0 "" "")] 3)] + "" + "* +{ + operands[1] = gen_label_rtx (); + output_asm_insn (AS1 (call,%X1), operands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[1])); + output_asm_insn (AS1 (pop%L0,%0), operands); + output_asm_insn (\"addl $%__GLOBAL_OFFSET_TABLE_+[.-%X1],%0\", operands); + RET; +}" + [(set_attr "memory" "none")]) + +(define_expand "epilogue" + [(const_int 1)] + "" + " +{ + ix86_expand_epilogue (); + DONE; +}") + +(define_insn "epilogue_set_stack_ptr" + [(set (reg:SI 7) (reg:SI 6)) + (clobber (reg:SI 6))] + "" + "* +{ + rtx xops [2]; + + xops[0] = frame_pointer_rtx; + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (mov%L0,%0,%1), xops); + RET; +}" + [(set_attr "memory" "none")]) + +(define_insn "leave" + [(const_int 2) + (clobber (reg:SI 6)) + (clobber (reg:SI 7))] + "" + "leave" + [(set_attr "memory" "none")]) + +(define_insn "pop" + [(set (match_operand:SI 0 "register_operand" "r") + (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))] + "" + "* +{ + output_asm_insn (AS1 (pop%L0,%P0), operands); + RET; +}" + [(set_attr "memory" "load")]) + +(define_expand "movstrsi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand:SI 3 "const_int_operand" "")) + (clobber (match_scratch:SI 4 "")) + (clobber (match_dup 5)) + (clobber (match_dup 6))])] + "" + " +{ + rtx addr0, addr1; + + if (GET_CODE (operands[2]) != CONST_INT) + FAIL; + + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + + operands[5] = addr0; + operands[6] = addr1; + + operands[0] = change_address (operands[0], VOIDmode, addr0); + operands[1] = change_address (operands[1], VOIDmode, addr1); +}") + +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi & %esi. + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "address_operand" "D")) + (mem:BLK (match_operand:SI 1 "address_operand" "S"))) + (use (match_operand:SI 2 "const_int_operand" "n")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_scratch:SI 4 "=&c")) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* +{ + rtx xops[2]; + + output_asm_insn (\"cld\", operands); + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL (operands[2]) & ~0x03) + { + xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff); + xops[1] = operands[4]; + + output_asm_insn (AS2 (mov%L1,%0,%1), xops); +#ifdef INTEL_SYNTAX + output_asm_insn (\"rep movsd\", xops); +#else + output_asm_insn (\"rep\;movsl\", xops); +#endif + } + if (INTVAL (operands[2]) & 0x02) + output_asm_insn (\"movsw\", operands); + if (INTVAL (operands[2]) & 0x01) + output_asm_insn (\"movsb\", operands); + } + else + abort (); + RET; +}") + +(define_expand "clrstrsi" + [(set (match_dup 3) (const_int 0)) + (parallel [(set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand:SI 1 "const_int_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_dup 3)) + (clobber (match_scratch:SI 4 "")) + (clobber (match_dup 5))])] + "" + " +{ + rtx addr0; + + if (GET_CODE (operands[1]) != CONST_INT) + FAIL; + + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + + operands[3] = gen_reg_rtx (SImode); + operands[5] = addr0; + + operands[0] = gen_rtx_MEM (BLKmode, addr0); +}") + +;; It might seem that operand 0 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi. + +(define_insn "*bzero" + [(set (mem:BLK (match_operand:SI 0 "address_operand" "D")) + (const_int 0)) + (use (match_operand:SI 1 "const_int_operand" "n")) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "register_operand" "a")) + (clobber (match_scratch:SI 4 "=&c")) + (clobber (match_dup 0))] + "" + "* +{ + rtx xops[2]; + + output_asm_insn (\"cld\", operands); + if (GET_CODE (operands[1]) == CONST_INT) + { + unsigned int count = INTVAL (operands[1]) & 0xffffffff; + if (count & ~0x03) + { + xops[0] = GEN_INT (count / 4); + xops[1] = operands[4]; + + /* K6: stos takes 1 cycle, rep stos takes 8 + %ecx cycles. + 80386: 4/5+5n (+2 for set of ecx) + 80486: 5/7+5n (+1 for set of ecx) + */ + if (count / 4 < ((int) ix86_cpu < (int)PROCESSOR_PENTIUM ? 4 : 6)) + { + do +#ifdef INTEL_SYNTAX + output_asm_insn (\"stosd\", xops); +#else + output_asm_insn (\"stosl\", xops); +#endif + while ((count -= 4) > 3); + } + else + { + output_asm_insn (AS2 (mov%L1,%0,%1), xops); +#ifdef INTEL_SYNTAX + output_asm_insn (\"rep stosd\", xops); +#else + output_asm_insn (\"rep\;stosl\", xops); +#endif + } + } + if (INTVAL (operands[1]) & 0x02) + output_asm_insn (\"stosw\", operands); + if (INTVAL (operands[1]) & 0x01) + output_asm_insn (\"stosb\", operands); + } + else + abort (); + RET; +}") + +(define_expand "cmpstrsi" + [(parallel [(set (match_operand:SI 0 "general_operand" "") + (compare:SI (match_operand:BLK 1 "general_operand" "") + (match_operand:BLK 2 "general_operand" ""))) + (use (match_operand:SI 3 "general_operand" "")) + (use (match_operand:SI 4 "immediate_operand" "")) + (clobber (match_dup 5)) + (clobber (match_dup 6)) + (clobber (match_dup 3))])] + "" + " +{ + rtx addr1, addr2; + + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0)); + operands[3] = copy_to_mode_reg (SImode, operands[3]); + + operands[5] = addr1; + operands[6] = addr2; + + operands[1] = gen_rtx_MEM (BLKmode, addr1); + operands[2] = gen_rtx_MEM (BLKmode, addr2); + +}") + +;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is +;; zero. Emit extra code to make sure that a zero-length compare is EQ. + +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi & %esi. + +;; ??? Most comparisons have a constant length, and it's therefore +;; possible to know that the length is non-zero, and to avoid the extra +;; code to handle zero-length compares. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=&r") + (compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S")) + (mem:BLK (match_operand:SI 2 "address_operand" "D")))) + (use (match_operand:SI 3 "register_operand" "c")) + (use (match_operand:SI 4 "immediate_operand" "i")) + (clobber (match_dup 1)) + (clobber (match_dup 2)) + (clobber (match_dup 3))] + "" + "* +{ + rtx xops[2], label; + + label = gen_label_rtx (); + + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (xor%L0,%0,%0), operands); + output_asm_insn (\"repz\;cmps%B2\", operands); + output_asm_insn (\"je %l0\", &label); + + xops[0] = operands[0]; + xops[1] = const1_rtx; + output_asm_insn (AS2 (sbb%L0,%0,%0), xops); + if (QI_REG_P (xops[0])) + output_asm_insn (AS2 (or%B0,%1,%b0), xops); + else + output_asm_insn (AS2 (or%L0,%1,%0), xops); + + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label)); + RET; +}") + +(define_insn "" + [(set (cc0) + (compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S")) + (mem:BLK (match_operand:SI 1 "address_operand" "D")))) + (use (match_operand:SI 2 "register_operand" "c")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_dup 0)) + (clobber (match_dup 1)) + (clobber (match_dup 2))] + "" + "* +{ + rtx xops[2]; + + cc_status.flags |= CC_NOT_SIGNED; + + xops[0] = gen_rtx_REG (QImode, 0); + xops[1] = CONST0_RTX (QImode); + + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (test%B0,%1,%0), xops); + return \"repz\;cmps%B2\"; +}") + + +;; Note, you cannot optimize away the branch following the bsfl by assuming +;; that the destination is not modified if the input is 0, since not all +;; x86 implementations do this. + +(define_expand "ffssi2" + [(set (match_operand:SI 0 "general_operand" "") + (ffs:SI (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + rtx label = gen_label_rtx (), temp = gen_reg_rtx (SImode); + + emit_insn (gen_ffssi_1 (temp, operands[1])); + emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, SImode, 0, 0); + emit_jump_insn (gen_bne (label)); + emit_move_insn (temp, constm1_rtx); + emit_label (label); + temp = expand_binop (SImode, add_optab, temp, const1_rtx, + operands[0], 0, OPTAB_WIDEN); + + if (temp != operands[0]) + emit_move_insn (operands[0], temp); + DONE; +}") + +(define_insn "ffssi_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))] + "" + "* return AS2 (bsf%L0,%1,%0);") + +(define_expand "ffshi2" + [(set (match_operand:SI 0 "general_operand" "") + (ffs:HI (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + rtx label = gen_label_rtx (), temp = gen_reg_rtx (HImode); + + emit_insn (gen_ffshi_1 (temp, operands[1])); + emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, HImode, 0, 0); + emit_jump_insn (gen_bne (label)); + emit_move_insn (temp, constm1_rtx); + emit_label (label); + temp = expand_binop (HImode, add_optab, temp, const1_rtx, + operands[0], 0, OPTAB_WIDEN); + + if (temp != operands[0]) + emit_move_insn (operands[0], temp); + DONE; +}") + +(define_insn "ffshi_1" + [(set (match_operand:HI 0 "register_operand" "=r") + (unspec:HI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))] + "" + "* return AS2 (bsf%W0,%1,%0);") + +;; These patterns match the binary 387 instructions for addM3, subM3, +;; mulM3 and divM3. There are three patterns for each of DFmode and +;; SFmode. The first is the normal insn, the second the same insn but +;; with one operand a conversion, and the third the same insn but with +;; the other operand a conversion. + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_387_op" + [(match_operand:DF 1 "nonimmediate_operand" "0,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(match_operand:XF 1 "register_operand" "0,f") + (match_operand:XF 2 "register_operand" "f,0")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:XF 2 "register_operand" "0,f")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(match_operand:XF 1 "register_operand" "0,f") + (float_extend:XF + (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_387_op" + [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:DF 2 "register_operand" "0,f")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_387_op" + [(match_operand:DF 1 "register_operand" "0,f") + (float_extend:DF + (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (match_operator:SF 3 "binary_387_op" + [(match_operand:SF 1 "nonimmediate_operand" "0,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) + +(define_expand "strlensi" + [(parallel [(set (match_dup 4) + (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" "")) + (match_operand:QI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")] 0)) + (clobber (match_dup 1))]) + (set (match_dup 5) + (not:SI (match_dup 4))) + (set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_dup 5) + (const_int -1)))] + "" + " +{ + if (TARGET_UNROLL_STRLEN && operands[2] == const0_rtx && optimize > 1) + { + rtx address; + rtx scratch; + + /* well it seems that some optimizer does not combine a call like + foo(strlen(bar), strlen(bar)); + when the move and the subtraction is done here. It does calculate + the length just once when these instructions are done inside of + output_strlen_unroll(). But I think since &bar[strlen(bar)] is + often used and I use one fewer register for the lifetime of + output_strlen_unroll() this is better. */ + scratch = gen_reg_rtx (SImode); + address = force_reg (SImode, XEXP (operands[1], 0)); + + /* move address to scratch-register + this is done here because the i586 can do the following and + in the same cycle with the following move. */ + if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4) + emit_insn (gen_movsi (scratch, address)); + + emit_insn (gen_movsi (operands[0], address)); + + if(TARGET_USE_Q_REG) + emit_insn (gen_strlensi_unroll5 (operands[0], + operands[3], + scratch, + operands[0])); + else + emit_insn (gen_strlensi_unroll4 (operands[0], + operands[3], + scratch, + operands[0])); + + /* gen_strlensi_unroll[45] returns the address of the zero + at the end of the string, like memchr(), so compute the + length by subtracting the startaddress. */ + emit_insn (gen_subsi3 (operands[0], operands[0], address)); + DONE; + } + + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); +}") + +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=&c") + (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D")) + (match_operand:QI 2 "immediate_operand" "a") + (match_operand:SI 3 "immediate_operand" "i")] 0)) + (clobber (match_dup 1))] + "" + "* +{ + rtx xops[2]; + + xops[0] = operands[0]; + xops[1] = constm1_rtx; + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + return \"repnz\;scas%B2\"; +}") + +/* Conditional move define_insns. */ + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "nonimmediate_operand" "") + (match_operand:SI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:SI 3 "nonimmediate_operand" "") + (match_operand:SI 4 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:SI 4 "nonimmediate_operand" "") + (match_operand:SI 5 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:SI 2 "nonimmediate_operand" "rm,0") + (match_operand:SI 3 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + "* return output_int_conditional_move (which_alternative, operands);") + +(define_expand "movhicc" + [(set (match_operand:HI 0 "register_operand" "") + (if_then_else:HI (match_operand 1 "comparison_operator" "") + (match_operand:HI 2 "nonimmediate_operand" "") + (match_operand:HI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:HI 3 "nonimmediate_operand" "") + (match_operand:HI 4 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:HI 4 "nonimmediate_operand" "") + (match_operand:HI 5 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:HI 2 "nonimmediate_operand" "rm,0") + (match_operand:HI 3 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + "* return output_int_conditional_move (which_alternative, operands);") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "register_operand" "") + (match_operand:SF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:SF 4 "register_operand" "f,f,0,0") + (match_operand:SF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:SF 4 "register_operand" "f,f,0,0") + (match_operand:SF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:SF 4 "register_operand" "") + (match_operand:SF 5 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:SF 2 "register_operand" "f,0") + (match_operand:SF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "register_operand" "") + (match_operand:DF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f,f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:DF 4 "register_operand" "f,f,0,0") + (match_operand:DF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f,f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:DF 4 "register_operand" "f,f,0,0") + (match_operand:DF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:DF 4 "register_operand" "") + (match_operand:DF 5 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:DF 2 "register_operand" "f,0") + (match_operand:DF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movxfcc" + [(set (match_operand:XF 0 "register_operand" "") + (if_then_else:XF (match_operand 1 "comparison_operator" "") + (match_operand:XF 2 "register_operand" "") + (match_operand:XF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f,f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:XF 4 "register_operand" "f,f,0,0") + (match_operand:XF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f,f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:XF 4 "register_operand" "f,f,0,0") + (match_operand:XF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:XF 3 "register_operand" "") + (match_operand:XF 4 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:XF 4 "register_operand" "") + (match_operand:XF 5 "register_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:XF 2 "register_operand" "f,0") + (match_operand:XF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movdicc" + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") + (match_operand:DI 2 "nonimmediate_operand" "") + (match_operand:DI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0") + (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0") + (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:DI 3 "nonimmediate_operand" "") + (match_operand:DI 4 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 5) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 7) (match_dup 9))) + (set (match_dup 6) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 8) (match_dup 10)))] + "split_di (&operands[0], 1, &operands[5], &operands[6]); + split_di (&operands[3], 1, &operands[7], &operands[8]); + split_di (&operands[4], 1, &operands[9], &operands[10]);") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:DI 4 "nonimmediate_operand" "") + (match_operand:DI 5 "nonimmediate_operand" "")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 6) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 8) (match_dup 10))) + (set (match_dup 7) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 9) (match_dup 11)))] + "split_di (&operands[0], 1, &operands[6], &operands[7]); + split_di (&operands[4], 1, &operands[8], &operands[9]); + split_di (&operands[5], 1, &operands[10], &operands[11]);") + +(define_insn "strlensi_unroll" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r")) + (match_operand:SI 2 "immediate_operand" "i,i")] 0)) + (clobber (match_scratch:SI 3 "=&q,&r"))] + "optimize > 1" + "* return output_strlen_unroll (operands);") + +;; the only difference between the following patterns is the register preference +;; on a pentium using a q-register saves one clock cycle per 4 characters + +(define_insn "strlensi_unroll4" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0")) + (match_operand:SI 1 "immediate_operand" "i,i") + (match_operand:SI 2 "register_operand" "+q,!r")] 0)) + (clobber (match_dup 2))] + "(TARGET_USE_ANY_REG && optimize > 1)" + "* return output_strlen_unroll (operands);") + +(define_insn "strlensi_unroll5" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0")) + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "register_operand" "+q")] 0)) + (clobber (match_dup 2))] + "(TARGET_USE_Q_REG && optimize > 1)" + "* return output_strlen_unroll (operands);" +) + +(define_insn "allocate_stack_worker" + [(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0))) + (clobber (match_dup 0))] + "TARGET_STACK_PROBE" + "* return AS1(call,__alloca);" + [(set_attr "memory" "none")]) + +(define_expand "allocate_stack" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" ""))) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 1)))] + "TARGET_STACK_PROBE" + " +{ +#ifdef CHECK_STACK_LIMIT + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < CHECK_STACK_LIMIT) + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, + operands[1])); + else +#endif + emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode, + operands[1]))); + + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; +}") + +(define_expand "exception_receiver" + [(const_int 0)] + "flag_pic" + " +{ + load_pic_register (1); + DONE; +}") diff --git a/gnu/egcs/gcc/config/i386/interix.c b/gnu/egcs/gcc/config/i386/interix.c new file mode 100644 index 00000000000..40062c70e15 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/interix.c @@ -0,0 +1,110 @@ +/* Subroutines for insn-output.c for Windows NT. + Copyright (C) 1998, 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. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "output.h" +#include "tree.h" +#include "flags.h" + +/* Return string which is the former assembler name modified with a + suffix consisting of an atsign (@) followed by the number of bytes of + arguments */ + +char * +gen_stdcall_suffix (decl) + tree decl; +{ + int total = 0; + /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead + of DECL_ASSEMBLER_NAME. */ + char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char *newsym; + + if (TYPE_ARG_TYPES (TREE_TYPE (decl))) + if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl)))) + == void_type_node) + { + tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + while (TREE_VALUE (formal_type) != void_type_node) + { + int parm_size + = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type))); + /* Must round up to include padding. This is done the same + way as in store_one_arg. */ + parm_size = ((parm_size + PARM_BOUNDARY - 1) + / PARM_BOUNDARY * PARM_BOUNDARY); + total += parm_size; + formal_type = TREE_CHAIN (formal_type); + } + } + + newsym = xmalloc (strlen (asmname) + 10); + sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT); + return IDENTIFIER_POINTER (get_identifier (newsym)); +} + +#if 0 +/* Turn this back on when the linker is updated to handle grouped + .data$ sections correctly. See corresponding note in i386/interix.h. + MK. */ + +/* Cover function for UNIQUE_SECTION. */ + +void +i386_pe_unique_section (decl, reloc) + tree decl; + int reloc; +{ + int len; + char *name,*string,*prefix; + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + /* Strip off any encoding in fnname. */ + STRIP_NAME_ENCODING (name, name); + + /* The object is put in, for example, section .text$foo. + The linker will then ultimately place them in .text + (everything from the $ on is stripped). Don't put + read-only data in .rdata section to avoid a PE linker + bug when .rdata$* grouped sections are used in code + without a .rdata section. */ + if (TREE_CODE (decl) == FUNCTION_DECL) + prefix = ".text$"; + else if (DECL_READONLY_SECTION (decl, reloc)) +#ifdef READONLY_DATA_SECTION + prefix = ".rdata$"; +#else + prefix = ".text$"; +#endif + else + prefix = ".data$"; + len = strlen (name) + strlen (prefix); + string = alloca (len + 1); + sprintf (string, "%s%s", prefix, name); + + DECL_SECTION_NAME (decl) = build_string (len, string); +} + +#endif /* 0 */ diff --git a/gnu/egcs/gcc/config/i386/isc.h b/gnu/egcs/gcc/config/i386/isc.h new file mode 100644 index 00000000000..6c1c4c72718 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/isc.h @@ -0,0 +1,96 @@ +/* Assembler-independent definitions for an Intel 386 running + Interactive Unix System V. Specifically, this is for recent versions + that support POSIX. */ + +/* Use crt1.o, not crt0.o, as a startup file, and crtn.o as a closing file. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shlib:%{posix:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}}\ + %{Xp:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}}\ + %{!posix:%{!Xp:%{pg:mcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}\ + %{p:-L/lib/libp} %{pg:-L/lib/libp}}}}\ + %{shlib:%{Xp:crtp1.o%s}%{posix:crtp1.o%s}%{!posix:%{!Xp:crt1.o%s}}}\ + crtbegin.o%s" + +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +/* Library spec */ +#undef LIB_SPEC +#define LIB_SPEC "%{shlib:-lc_s} %{posix:-lcposix} %{Xp:-lcposix} -lc -lg" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{Xp:-D_POSIX_SOURCE}" + +/* ISC 2.2 uses `char' for `wchar_t'. */ +#undef WCHAR_TYPE +#define WCHAR_TYPE "char" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_UNIT + +#if 0 +/* This is apparently not true: ISC versions up to 3.0, at least, use + the standard calling sequence in which the called function pops the + extra arg. */ +/* caller has to pop the extra argument passed to functions that return + structures. */ + +#undef RETURN_POPS_ARGS +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \ + : (TARGET_RTD \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) ? (SIZE) \ + : 0) +/* On other 386 systems, the last line looks like this: + : (aggregate_value_p (TREE_TYPE (FUNTYPE))) ? GET_MODE_SIZE (Pmode) : 0) */ +#endif + +/* Handle #pragma pack and #pragma weak. */ +#define HANDLE_SYSV_PRAGMA + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387, ie, + (TARGET_80387 | TARGET_FLOAT_RETURNS_IN_80387) + + ISC's software emulation of a 387 fails to handle the `fucomp' + opcode. fucomp is only used when generating IEEE compliant code. + So don't make TARGET_IEEE_FP default for ISC. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) + +/* The ISC 2.0.2 software FPU emulator apparently can't handle + 80-bit XFmode insns, so don't generate them. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* The ISC assembler does not like a .file directive with a name + longer than 14 characters. Truncating it will not permit + debugging to work properly, but at least we won't get an error + message. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + int len = strlen (main_input_filename); \ + char *na = main_input_filename + len; \ + char shorter[15]; \ + /* NA gets MAIN_INPUT_FILENAME sans directory names. */\ + while (na > main_input_filename) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + strncpy (shorter, na, 14); \ + shorter[14] = 0; \ + fprintf (FILE, "\t.file\t"); \ + output_quoted_string (FILE, shorter); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Work around assembler forward label references generated in exception + handling code. */ +#define DWARF2_UNWIND_INFO 0 diff --git a/gnu/egcs/gcc/config/i386/isccoff.h b/gnu/egcs/gcc/config/i386/isccoff.h new file mode 100644 index 00000000000..595c7d98fe3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/isccoff.h @@ -0,0 +1,12 @@ +/* Definitions for Intel 386 running Interactive Unix System V. + Specifically, this is for recent versions that support POSIX; + for version 2.0.2, use configuration option i386-sysv instead. + (But set TARGET_DEFAULT to (MASK_80307 | MASK_FLOAT_RETURNS) + if you do that, if you don't have a real 80387.) */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "i386/sysv3.h" + +/* But with a few changes. */ +#include "i386/isc.h" diff --git a/gnu/egcs/gcc/config/i386/iscdbx.h b/gnu/egcs/gcc/config/i386/iscdbx.h new file mode 100644 index 00000000000..6c2d42e470d --- /dev/null +++ b/gnu/egcs/gcc/config/i386/iscdbx.h @@ -0,0 +1,43 @@ +/* Definitions for Intel 386 running Interactive Unix System V, + using dbx-in-coff encapsulation. + Specifically, this is for recent versions that support POSIX. + Copyright (C) 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Mostly it's like AT&T Unix System V with dbx-in-coff. */ + +#include "i386/svr3dbx.h" + +/* But with a few changes. */ +#undef ENDFILE_SPEC +#include "i386/isc.h" + +/* Overridden defines for ifile usage. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!r:%{!z:svr3.ifile%s}%{z:svr3z.ifile%s}}\ + %{!shlib:%{posix:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}}\ + %{Xp:%{pg:mcrtp1.o%s}%{!pg:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}}\ + %{!posix:%{!Xp:%{pg:mcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}\ + %{p:-L/usr/lib/libp} %{pg:-L/usr/lib/libp}}\ + %{shlib:%{posix:crtp1.o%s}%{Xp:crtp1.o%s}%{!posix:%{!Xp:crt1.o%s}}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtn.o%s" diff --git a/gnu/egcs/gcc/config/i386/linux-aout.h b/gnu/egcs/gcc/config/i386/linux-aout.h new file mode 100644 index 00000000000..de81d878317 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/linux-aout.h @@ -0,0 +1,74 @@ +/* Definitions for Intel 386 running Linux-based GNU systems using a.out. + Copyright (C) 1992, 1994, 1995, 1997, 1998 Free Software Foundation, Inc. + Contributed by H.J. Lu (hjl@nynexst.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. */ + +/* This is tested by i386/gas.h. */ +#define YES_UNDERSCORES + +#include <i386/gstabs.h> +#include <linux-aout.h> /* some common stuff */ + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}" + +#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 + +/* 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 + +#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 -static}}}" +#endif + + +#undef LINK_SPEC +#define LINK_SPEC "-m i386linux" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" diff --git a/gnu/egcs/gcc/config/i386/linux-oldld.h b/gnu/egcs/gcc/config/i386/linux-oldld.h new file mode 100644 index 00000000000..4e3085bc2ca --- /dev/null +++ b/gnu/egcs/gcc/config/i386/linux-oldld.h @@ -0,0 +1,75 @@ +/* Definitions for Intel 386 running Linux-based GNU systems with pre-BFD + a.out linkers. + Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. + Contributed by Michael Meissner (meissner@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. */ + +/* This is tested by i386/gas.h. */ +#define YES_UNDERSCORES + +#include <i386/gstabs.h> +#include <linux-aout.h> /* some common stuff */ + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}" + +#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 + +/* 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 + +#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 -static}}}" +#endif + + +#undef LINK_SPEC +#define LINK_SPEC "" + +/* Get perform_* macros to build libgcc.a. */ +#include <i386/perform.h> diff --git a/gnu/egcs/gcc/config/i386/linux.h b/gnu/egcs/gcc/config/i386/linux.h new file mode 100644 index 00000000000..7b368f8e5fb --- /dev/null +++ b/gnu/egcs/gcc/config/i386/linux.h @@ -0,0 +1,236 @@ +/* Definitions for Intel 386 running Linux-based GNU systems with ELF format. + Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Eric Youngdale. + Modified for stabs-in-ELF by H.J. Lu. + +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 LINUX_DEFAULT_ELF + +/* A lie, I guess, but the general idea behind linux/ELF is that we are + supposed to be outputting something that will assemble under SVr4. + This gets us pretty close. */ +#include <i386/i386.h> /* Base i386 target machine definitions */ +#include <i386/att.h> /* Use the i386 AT&T assembler syntax */ +#include <linux.h> /* some common stuff */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 Linux/ELF)"); + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 1 + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +/* Copy this from the svr4 specifications... */ +/* Define the register numbers to be used in Dwarf debugging information. + The SVR4 reference port C compiler uses the following register numbers + in its Dwarf output code: + 0 for %eax (gnu regno = 0) + 1 for %ecx (gnu regno = 2) + 2 for %edx (gnu regno = 1) + 3 for %ebx (gnu regno = 3) + 4 for %esp (gnu regno = 7) + 5 for %ebp (gnu regno = 6) + 6 for %esi (gnu regno = 4) + 7 for %edi (gnu regno = 5) + The following three DWARF register numbers are never generated by + the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 + believes these numbers have these meanings. + 8 for %eip (no gnu equivalent) + 9 for %eflags (no gnu equivalent) + 10 for %trapno (no gnu equivalent) + It is not at all clear how we should number the FP stack registers + for the x86 architecture. If the version of SDB on x86/svr4 were + a bit less brain dead with respect to floating-point then we would + have a precedent to follow with respect to DWARF register numbers + for x86 FP registers, but the SDB on x86/svr4 is so completely + broken with respect to FP registers that it is hardly worth thinking + of it as something to strive for compatibility with. + The version of x86/svr4 SDB I have at the moment does (partially) + seem to believe that DWARF register number 11 is associated with + the x86 register %st(0), but that's about all. Higher DWARF + register numbers don't seem to be associated with anything in + particular, and even for DWARF regno 11, SDB only seems to under- + stand that it should say that a variable lives in %st(0) (when + asked via an `=' command) if we said it was in DWARF regno 11, + but SDB still prints garbage when asked for the value of the + variable in question (via a `/' command). + (Also note that the labels SDB prints for various FP stack regs + when doing an `x' command are all wrong.) + Note that these problems generally don't affect the native SVR4 + C compiler because it doesn't allow the use of -O with -g and + because when it is *not* optimizing, it allocates a memory + location for each floating-point variable, and the memory + location is what gets described in the DWARF AT_location + attribute for the variable in question. + Regardless of the severe mental illness of the x86/svr4 SDB, we + do something sensible here and we use the following DWARF + register numbers. Note that these are all stack-top-relative + numbers. + 11 for %st(0) (gnu regno = 8) + 12 for %st(1) (gnu regno = 9) + 13 for %st(2) (gnu regno = 10) + 14 for %st(3) (gnu regno = 11) + 15 for %st(4) (gnu regno = 12) + 16 for %st(5) (gnu regno = 13) + 17 for %st(6) (gnu regno = 14) + 18 for %st(7) (gnu regno = 15) +*/ +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +#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 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__i386__ -Dlinux -Asystem(posix)" + +#undef CPP_SPEC +#ifdef USE_GNULIBC_1 +#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}" +#else +#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" +#endif + +#undef CC1_SPEC +#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" + +/* Provide a LINK_SPEC appropriate for 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 elf_i386 %{shared:-shared} \ + %{!shared: \ + %{!ibcs: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/elf/ld-linux.so.1} \ + %{!rpath:-rpath /lib/elf/}} %{static:-static}}}" +#else +#define LINK_SPEC "-m elf_i386 %{shared:-shared} \ + %{!shared: \ + %{!ibcs: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.1}} \ + %{static:-static}}}" +#endif +#else +#define LINK_SPEC "-m elf_i386 %{shared:-shared} \ + %{!shared: \ + %{!ibcs: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \ + %{static:-static}}}" +#endif + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +/* 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) + +/* A C statement to output to the stdio stream FILE an assembler + command to advance the location counter to a multiple of 1<<LOG + bytes if it is within MAX_SKIP bytes. + + This is used to align code labels according to Intel recommendations. */ + +#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN +#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \ + do { \ + if ((LOG) != 0) { \ + if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + } \ + } while (0) +#endif diff --git a/gnu/egcs/gcc/config/i386/lynx-ng.h b/gnu/egcs/gcc/config/i386/lynx-ng.h new file mode 100644 index 00000000000..ec4e2961692 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/lynx-ng.h @@ -0,0 +1,37 @@ +/* Definitions for Intel 386 running LynxOS, using Lynx's old as and ld. + 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 <i386/gstabs.h> +#include <lynx-ng.h> + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -DI386 -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(i386) -Amachine(i386)" + +/* Provide required defaults for linker switches. */ + +#undef LINK_SPEC +#define LINK_SPEC "-P1000 %{msystem-v:-V} %{mcoff:-k}" + +/* Apparently LynxOS clobbers ebx when you call into the OS. */ + +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } diff --git a/gnu/egcs/gcc/config/i386/lynx.h b/gnu/egcs/gcc/config/i386/lynx.h new file mode 100644 index 00000000000..73111f916a5 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/lynx.h @@ -0,0 +1,39 @@ +/* Definitions for Intel 386 running LynxOS. + 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 <i386/gstabs.h> +#include <lynx.h> + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -DI386 -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(i386) -Amachine(i386)" + +/* The prefix to add to user-visible assembler symbols. */ + +/* Override the svr3 convention of adding a leading underscore. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* Apparently LynxOS clobbers ebx when you call into the OS. */ + +#undef CALL_USED_REGISTERS +#define CALL_USED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg*/ \ +{ 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } diff --git a/gnu/egcs/gcc/config/i386/mach.h b/gnu/egcs/gcc/config/i386/mach.h new file mode 100644 index 00000000000..4b7cf37e54d --- /dev/null +++ b/gnu/egcs/gcc/config/i386/mach.h @@ -0,0 +1,20 @@ +/* Configuration for an i386 running Mach as the target machine. */ + +/* We do want to add an underscore to the front of each user symbol. + i386/gas.h checks this. */ +#define YES_UNDERSCORES + +#include "i386/gstabs.h" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -DMACH -Asystem(unix) -Asystem(mach) -Acpu(i386) -Amachine(i386)" + +/* Specify extra dir to search for include files. */ +#define SYSTEM_INCLUDE_DIR "/usr/mach/include" + +/* 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/gnu/egcs/gcc/config/i386/mingw32.h b/gnu/egcs/gcc/config/i386/mingw32.h new file mode 100644 index 00000000000..552cbcd1932 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/mingw32.h @@ -0,0 +1,94 @@ +/* Operating system specific defines to be used when targeting GCC for + hosting on Windows32, using GNU tools and the Windows32 API Library, + as distinct from winnt.h, which is used to build GCC for use with a + windows style library and tool set and uses the Microsoft tools. + Copyright (C) 1997, 1998, 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. */ + +/* Most of this is the same as for cygwin, except for changing some + specs. */ + +#include "i386/cygwin.h" + +/* Please keep changes to CPP_PREDEFINES in sync with i386/crtdll. The + only difference between the two should be __MSVCRT__ needed to + distinguish MSVC from CRTDLL runtime in mingw headers. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -D_WIN32 -DWIN32 -D__WIN32__ \ + -D__MINGW32__=0.2 -D__MSVCRT__ -DWINNT -D_X86_=1 -D__STDC__=1\ + -D__stdcall=__attribute__((__stdcall__)) \ + -D_stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ + -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + +/* Specific a different directory for the standard include files. */ +#undef STANDARD_INCLUDE_DIR +#define STANDARD_INCLUDE_DIR "/usr/local/i386-mingw32/include" + +#define STANDARD_INCLUDE_COMPONENT "MINGW32" + +#undef CPP_SPEC +#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE}" + +/* For Windows applications, include more libraries, but always include + kernel32. */ +#undef LIB_SPEC +#define LIB_SPEC "%{mwindows:-lgdi32 -lcomdlg32} \ + -luser32 -lkernel32 -ladvapi32 -lshell32" + +/* Include in the mingw32 libraries with libgcc */ +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lmsvcrt" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s}" + +/* MS runtime does not need a separate math library. */ +#define MATH_LIBRARY "" + +/* Output STRING, a string representing a filename, to FILE. We canonicalize + it to be in MS-DOS format. */ +#define OUTPUT_QUOTED_STRING(FILE, STRING) \ +do { \ + char c; \ + \ + putc ('\"', asm_file); \ + if (STRING[1] == ':' \ + && (STRING[2] == '/' || STRING[2] == '\\')) \ + { \ + putc ('/', asm_file); \ + putc ('/', asm_file); \ + putc (*string, asm_file); \ + string += 2; \ + } \ + \ + while ((c = *string++) != 0) \ + { \ + if (c == '\\') \ + c = '/'; \ + \ + if (c == '\"') \ + putc ('\\', asm_file); \ + putc (c, asm_file); \ + } \ + \ + putc ('\"', asm_file); \ +} while (0) + diff --git a/gnu/egcs/gcc/config/i386/moss.h b/gnu/egcs/gcc/config/i386/moss.h new file mode 100644 index 00000000000..d2548e3a5b9 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/moss.h @@ -0,0 +1,35 @@ +/* Definitions for Intel 386 running MOSS + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Bryan Ford <baford@cs.utah.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. */ + +/* I believe in reuse... */ +#include "i386/linux.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ELF__ -Di386 -Dmoss -Asystem(posix) -Acpu(i386) -Amachine(i386)" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crt0.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtn.o%s" + +#undef LINK_SPEC + diff --git a/gnu/egcs/gcc/config/i386/netbsd.h b/gnu/egcs/gcc/config/i386/netbsd.h new file mode 100644 index 00000000000..d9f06469e62 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/netbsd.h @@ -0,0 +1,87 @@ +/* This is tested by i386gas.h. */ +#define YES_UNDERSCORES + +#include <i386/gstabs.h> + +/* Get perform_* macros to build libgcc.a. */ +#include <i386/perform.h> + +/* Get generic NetBSD definitions. */ +#include <netbsd.h> + +/* This goes away when the math-emulator is fixed */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Di386 -D__NetBSD__ -Asystem(unix) -Asystem(NetBSD) -Acpu(i386) -Amachine(i386)" + +#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 + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/* The following macros are stolen from i386v4.h */ +/* These have to be defined to get PIC code correct */ + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* 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 + +/* i386 netbsd still uses old binutils that don't insert nops by default + when the .align directive demands to insert extra space in the text + segment. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) + +/* Profiling routines, partially copied from i386/osfrose.h. */ + +/* Redefine this to use %eax instead of %edx. */ +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tcall mcount@PLT\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +/* Until they use ELF or something that handles dwarf2 unwinds + and initialization stuff better. */ +#define DWARF2_UNWIND_INFO 0 + diff --git a/gnu/egcs/gcc/config/i386/next.h b/gnu/egcs/gcc/config/i386/next.h new file mode 100644 index 00000000000..bbc0e6b3061 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/next.h @@ -0,0 +1,233 @@ +/* Target definitions for GNU compiler for Intel x86 CPU running NeXTSTEP + Copyright (C) 1993, 1995, 1996, 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. */ + +#include "i386/gas.h" +#include "nextstep.h" + +/* By default, target has a 80387, with IEEE FP. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP) + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Machines that use the AT&T assembler syntax + also return floating point values in an FP register. + 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. */ + +#undef VALUE_REGNO +#define VALUE_REGNO(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode \ + ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#undef FUNCTION_VALUE_REGNO_P +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG) + +#ifdef REAL_VALUE_TO_TARGET_LONG_DOUBLE +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ + do { \ + long hex[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, hex); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "\t.long 0x%x\n\t.long 0x%x\n\t.long 0x%x\n", \ + hex[0], hex[1], hex[2]); \ + else \ + fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n\t.long 0x%lx\n", \ + hex[0], hex[1], hex[2]); \ + } while (0) +#endif + +#ifdef REAL_VALUE_TO_TARGET_DOUBLE +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ + do { \ + long hex[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE (VALUE, hex); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "\t.long 0x%x\n\t.long 0x%x\n", hex[0], hex[1]); \ + else \ + fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", hex[0], hex[1]); \ + } while (0) +#endif + +/* This is how to output an assembler line defining a `float' constant. */ + +#ifdef REAL_VALUE_TO_TARGET_SINGLE +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ + do { \ + long hex; \ + REAL_VALUE_TO_TARGET_SINGLE (VALUE, hex); \ + if (sizeof (int) == sizeof (long)) \ + fprintf (FILE, "\t.long 0x%x\n", hex); \ + else \ + fprintf (FILE, "\t.long 0x%lx\n", hex); \ + } while (0) +#endif + +/* A C statement or statements which output an assembler instruction + opcode to the stdio stream STREAM. The macro-operand PTR is a + variable of type `char *' which points to the opcode name in its + "internal" form--the form that is written in the machine description. + + GAS version 1.38.1 doesn't understand the `repz' opcode mnemonic. + So use `repe' instead. */ + +#undef ASM_OUTPUT_OPCODE +#define ASM_OUTPUT_OPCODE(STREAM, PTR) \ +{ \ + if ((PTR)[0] == 'r' \ + && (PTR)[1] == 'e' \ + && (PTR)[2] == 'p') \ + { \ + if ((PTR)[3] == 'z') \ + { \ + fprintf (STREAM, "repe"); \ + (PTR) += 4; \ + } \ + else if ((PTR)[3] == 'n' && (PTR)[4] == 'z') \ + { \ + fprintf (STREAM, "repne"); \ + (PTR) += 5; \ + } \ + } \ +} + +/* Define macro used to output shift-double opcodes when the shift + count is in %cl. Some assemblers require %cl as an argument; + some don't. + + GAS requires the %cl argument, so override unx386.h. */ + +#undef SHIFT_DOUBLE_OMITS_COUNT +#define SHIFT_DOUBLE_OMITS_COUNT 0 + +/* Print opcodes the way that GAS expects them. */ +#define GAS_MNEMONICS 1 + +/* Names to predefine in the preprocessor for this target machine. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -DNeXT -Dunix -D__MACH__ -D__LITTLE_ENDIAN__ -D__ARCHITECTURE__=\"i386\" -Asystem(unix) -Asystem(mach) -Acpu(i386) -Amachine(i386)" + +/* This accounts for the return pc and saved fp on the i386. */ + +#define OBJC_FORWARDING_STACK_OFFSET 8 +#define OBJC_FORWARDING_MIN_OFFSET 8 + +/* We do not want a dot in internal labels. */ + +#undef LPREFIX +#define LPREFIX "L" + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, "%s%d:\n", PREFIX, NUM) + +/* 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" + +#undef ASM_OUTPUT_REG_PUSH +#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ + fprintf (FILE, "\tpushl %se%s\n", "%", reg_names[REGNO]) + +#undef ASM_OUTPUT_REG_POP +#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ + fprintf (FILE, "\tpopl %se%s\n", "%", reg_names[REGNO]) + +/* This is being overridden because the default i386 configuration + generates calls to "_mcount". NeXT system libraries all use + "mcount". */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +/* BEGIN Calling Convention CHANGES */ + +/* These changes violate the Intel/Unix ABI. Specifically, they + change the way that space for a block return value is passed to a + function. The ABI says that the pointer is passed on the stack. + We change to pass the pointer in %ebx. This makes the NeXT + Objective-C forwarding mechanism possible to implement on an i386. */ + +/* Do NOT pass address of structure values on the stack. */ + +#undef STRUCT_VALUE_INCOMING +#undef STRUCT_VALUE + +/* Pass them in %ebx. */ + +#undef STRUCT_VALUE_REGNUM +#define STRUCT_VALUE_REGNUM 3 + +/* Because we are passing the pointer in a register, we don't need to + rely on the callee to pop it. */ + +#undef RETURN_POPS_ARGS +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE \ + ? 0 \ + : (TARGET_RTD \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) ? (SIZE) : 0) + +/* END Calling Convention CHANGES */ + +/* NeXT still uses old binutils that don't insert nops by default + when the .align directive demands to insert extra space in the text + segment. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) diff --git a/gnu/egcs/gcc/config/i386/openbsd.h b/gnu/egcs/gcc/config/i386/openbsd.h new file mode 100644 index 00000000000..dc84f892c16 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/openbsd.h @@ -0,0 +1,136 @@ +/* Configuration for an OpenBSD i386 target. + + Copyright (C) 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. */ + +/* This is tested by i386gas.h. */ +#define YES_UNDERSCORES + +#include <i386/gstabs.h> + +/* Get perform_* macros to build libgcc.a. */ +#include <i386/perform.h> + +/* Get generic OpenBSD definitions. */ +#define OBSD_OLD_GAS +#include <openbsd.h> + +/* This goes away when the math-emulator is fixed */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) + +/* Run-time target specifications */ +#define CPP_PREDEFINES "-D__unix__ -D__i386__ -D__OpenBSD__ -Asystem(unix) -Asystem(OpenBSD) -Acpu(i386) -Amachine(i386)" + +/* Layout of source language data types. */ + +/* This must 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_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +/* Assembler format: overall framework. */ + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +/* The following macros were originally stolen from i386v4.h. + These have to be defined to get PIC code correct. */ + +/* Assembler format: dispatch tables. */ + +/* How to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Assembler format: sections. */ + +/* Indicate when jump tables go in the text section. This is + necessary when compiling PIC code. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +/* Stack & calling: aggregate returns. */ + +/* 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 + +/* Assembler format: alignment output. */ + +/* Kludgy test: when gas is upgraded, it will have p2align, and no problems + with nops. */ +#ifndef HAVE_GAS_MAX_SKIP_P2ALIGN +/* i386 OpenBSD still uses an older gas that doesn't insert nops by default + when the .align directive demands to insert extra space in the text + segment. */ +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG)) +#endif + +/* Stack & calling: profiling. */ + +/* OpenBSD's profiler recovers all information from the stack pointer. + The icky part is not here, but in machine/profile.h. */ +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fputs (flag_pic ? "\tcall mcount@PLT\n": "\tcall mcount\n", FILE); + +/* Assembler format: exception region output. */ + +/* All configurations that don't use elf must be explicit about not using + dwarf unwind information. egcs doesn't try too hard to check internal + configuration files... */ +#define DWARF2_UNWIND_INFO 0 + +/* Assembler format: alignment output. */ + +/* A C statement to output to the stdio stream FILE an assembler + command to advance the location counter to a multiple of 1<<LOG + bytes if it is within MAX_SKIP bytes. + + This will be used to align code labels according to Intel + recommendations, in prevision of binutils upgrade. */ +#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN +#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \ + do { \ + if ((LOG) != 0) { \ + if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \ + else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \ + } \ + } while (0) +#endif + +/* Note that we pick up ASM_OUTPUT_MI_THUNK from unix.h. */ + diff --git a/gnu/egcs/gcc/config/i386/os2.h b/gnu/egcs/gcc/config/i386/os2.h new file mode 100644 index 00000000000..8bbab361f98 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/os2.h @@ -0,0 +1,76 @@ +/* Definitions of target machine for GNU compiler + for an Intel i386 or later processor running OS/2 2.x. + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + Contributed by Samuel Figueroa (figueroa@cs.nyu.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. */ + +#ifndef DEFAULT_TARGET_MACHINE +#define DEFAULT_TARGET_MACHINE "i386-os2" +#endif +#ifndef LINK_SPEC +#define LINK_SPEC "/st:1048576/pm:vio/noi/a:16/e/bas:65536/nol" +#endif +#ifndef LIB_SPEC +#define LIB_SPEC "libgcc libc" +#endif +#ifndef STARTFILE_SPEC +#define STARTFILE_SPEC "libcrt.lib" +#endif +#ifndef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "\\gcc\\bin\\" +#endif +#ifndef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "\\gcc\\lib\\" +#endif +#ifndef LOCAL_INCLUDE_DIR +#define LOCAL_INCLUDE_DIR "\\gcc\\include" +#endif + +#define YES_UNDERSCORES +#include "i386/gstabs.h" + +#define USE_COLLECT + +#define BIGGEST_FIELD_ALIGNMENT \ + (maximum_field_alignment ? maximum_field_alignment : 32) + +extern int maximum_field_alignment; + +#undef PCC_BITFIELD_TYPE_MATTERS +#define PCC_BITFIELD_TYPE_MATTERS (maximum_field_alignment == 0) + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ + (MODE) = SImode; + +/* Define this if function arguments should also be promoted using the above + procedure. */ + +#define PROMOTE_FUNCTION_ARGS + +/* Likewise, if the function return value is promoted. */ + +#define PROMOTE_FUNCTION_RETURN diff --git a/gnu/egcs/gcc/config/i386/osf1-ci.asm b/gnu/egcs/gcc/config/i386/osf1-ci.asm new file mode 100644 index 00000000000..a0f077304a8 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osf1-ci.asm @@ -0,0 +1,65 @@ +! crti.s for OSF/1, x86; derived from sol2-ci.asm. + +! Copyright (C) 1993, 1998 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 just supplies labeled starting points for the .init and .fini +! sections. It is linked in before the values-Xx.o files and also before +! crtbegin.o. + + .file "crti.s" + .ident "GNU C crti.s" + + .section .init + .globl _init + .type _init,@function +_init: + + .section .fini + .globl _fini + .type _fini,@function +_fini: + +.globl _init_init_routine +.data + .align 4 + .type _init_init_routine,@object + .size _init_init_routine,4 +_init_init_routine: + .long _init +.globl _init_fini_routine + .align 4 + .type _init_fini_routine,@object + .size _init_fini_routine,4 +_init_fini_routine: + .long _fini diff --git a/gnu/egcs/gcc/config/i386/osf1-cn.asm b/gnu/egcs/gcc/config/i386/osf1-cn.asm new file mode 100644 index 00000000000..a10298fd288 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osf1-cn.asm @@ -0,0 +1,46 @@ +! crtn.s for OSF/1, x86; derived from sol2-cn.asm. + +! Copyright (C) 1993, 1998 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 just supplies returns for the .init and .fini sections. It is +! linked in after all other files. + + .file "crtn.o" + .ident "GNU C crtn.o" + + .section .init + ret $0x0 + + .section .fini + ret $0x0 diff --git a/gnu/egcs/gcc/config/i386/osf1elf.h b/gnu/egcs/gcc/config/i386/osf1elf.h new file mode 100644 index 00000000000..003400b0dfe --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osf1elf.h @@ -0,0 +1,260 @@ +/* OSF/1 1.3 now is compitable with SVR4, so include sysv4.h, and + put difference here. */ + +#include <stdio.h> +#include "i386/sysv4.h" /* Base i386 target machine definitions */ +#define _sys_siglist sys_siglist +extern char *sys_siglist[]; + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 OSF/1)"); + +/* WORD_SWITCH_TAKES_ARG defined in svr4 is not correct. We also + need an extra -soname */ +#undef WORD_SWITCH_TAKES_ARG +#define WORD_SWITCH_TAKES_ARG(STR) \ + (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \ + || !strcmp (STR, "Tdata") || !strcmp (STR, "Ttext") \ + || !strcmp (STR, "Tbss") || !strcmp (STR, "soname")) + +/* Note, -fpic and -fPIC are equivalent */ +#undef CPP_SPEC +#define CPP_SPEC "\ +%{fpic: -D__SHARED__} %{fPIC: %{!fpic: -D__SHARED__}} \ +%{.S: %{!ansi:%{!traditional:%{!traditional-cpp:%{!ftraditional: -traditional}}}}} \ +%{.S: -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \ +%{.cc: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.cxx: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.C: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.m: -D__LANGUAGE_OBJECTIVE_C} \ +%{!.S: -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}}" + +/* -mmcount or -mno-mcount should be used with -pg or -p */ +#undef CC1_SPEC +#define CC1_SPEC "%{p: %{!mmcount: %{!mno-mcount: -mno-mcount }}} \ +%{!p: %{pg: %{!mmcount: %{!mno-mcount: -mno-mcount }}}}" + +/* Note, -D__NO_UNDERSCORES__ -D__ELF__ are provided in the older version of + OSF/1 gcc. We keep them here, so that old /usr/include/i386/asm.h works. + */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-D__NO_UNDERSCORES__ -D__ELF__ -DOSF -DOSF1 -Di386 -Dunix -Asystem(xpg4) -Asystem(osf1) -Acpu(i386) -Amachine(i386)" + +/* current OSF/1 doesn't provide separate crti.o and gcrti.o (and also, crtn.o + and gcrtn.o) for profile. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{!shared: \ + %{!symbolic: \ + %{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}\ + crti.o%s \ + crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +#undef ASM_SPEC +#define ASM_SPEC "%{v*: -v}" + +#undef LINK_SPEC +#define LINK_SPEC "%{v*: -v} \ + %{h*} %{z*} \ + %{dy:-call_shared} %{dn:-static} \ + %{static:-static} \ + %{shared:-shared} \ + %{call_shared:-call_shared} \ + %{symbolic:-Bsymbolic -shared -call_shared} \ + %{!dy: %{!dn: %{!static: %{!shared: %{!symbolic: \ + %{noshrlib: -static } \ + %{!noshrlib: -call_shared}}}}}}" + +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/usr/ccs/gcc/" + +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/usr/ccs/lib/" + +/* Define this macro meaning that gcc should find the library 'libgcc.a' + by hand, rather than passing the argument '-lgcc' to tell the linker + to do the search */ +#define LINK_LIBGCC_SPECIAL + +/* This goes with LINK_LIBGCC_SPECIAL, we need tell libgcc.a differently */ +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "%{!shared:%{!symbolic:libgcc.a%s}}" + +/* A C statement to output assembler commands which will identify the object + file as having been compile with GNU CC. We don't need or want this for + OSF1. */ +#undef ASM_IDENTIFY_GCC +#define ASM_IDENTIFY_GCC(FILE) + +/* Identify the front-end which produced this file. To keep symbol + space down, and not confuse kdb, only do this if the language is + not C. */ +#define ASM_IDENTIFY_LANGUAGE(STREAM) \ +{ \ + if (strcmp (lang_identify (), "c") != 0) \ + output_lang_identify (STREAM); \ +} + +/* Specify size_t, ptrdiff_t, and wchar_t types. */ +#undef SIZE_TYPE +#undef PTRDIFF_TYPE +#undef WCHAR_TYPE +#undef WCHAR_TYPE_SIZE + +#define SIZE_TYPE "long unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_TYPE "unsigned int" +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +/* Turn off long double being 96 bits. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Work with OSF/1 profile */ +#define MASK_NO_MCOUNT 000200000000 /* profiling uses mcount_ptr */ + +#define TARGET_MCOUNT ((target_flags & MASK_NO_MCOUNT) == 0) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "mcount", -MASK_NO_MCOUNT, "Profiling uses mcount" }, \ + { "no-mcount", MASK_NO_MCOUNT, "" }, + +/* 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. + + We override it here to allow for the new profiling code to go before + the prologue and the old mcount code to go after the prologue (and + after %ebx has been set up for ELF shared library support). */ +#if 0 +#define OSF_PROFILE_BEFORE_PROLOGUE \ + (!TARGET_MCOUNT \ + && !current_function_needs_context \ + && (!flag_pic \ + || !frame_pointer_needed \ + || (!current_function_uses_pic_offset_table \ + && !current_function_uses_const_pool))) +#else +#define OSF_PROFILE_BEFORE_PROLOGUE 0 +#endif +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +do \ + { \ + char *prefix = ""; \ + char *lprefix = LPREFIX; \ + int labelno = profile_label_no; \ + \ + if (profile_flag && OSF_PROFILE_BEFORE_PROLOGUE) \ + { \ + if (!flag_pic) \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall *%s_mcount_ptr\n", prefix); \ + } \ + \ + else \ + { \ + static int call_no = 0; \ + \ + fprintf (FILE, "\tcall %sPc%d\n", lprefix, call_no); \ + fprintf (FILE, "%sPc%d:\tpopl %%eax\n", lprefix, call_no); \ + fprintf (FILE, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%sPc%d],%%eax\n", \ + lprefix, call_no++); \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%eax),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tmovl %s_mcount_ptr@GOT(%%eax),%%eax\n", \ + prefix); \ + fprintf (FILE, "\tcall *(%%eax)\n"); \ + } \ + } \ + \ + function_prologue (FILE, SIZE); \ + } \ +while (0) + +/* A C statement or compound statement to output to FILE some assembler code to + call the profiling subroutine `mcount'. Before calling, the assembler code + must load the address of a counter variable into a register where `mcount' + expects to find the address. The name of this variable is `LP' followed by + the number LABELNO, so you would generate the name using `LP%d' in a + `fprintf'. + + The details of how the address should be passed to `mcount' are determined + by your operating system environment, not by GNU CC. To figure them out, + compile a small program for profiling using the system's installed C + compiler and look at the assembler code that results. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +do \ + { \ + if (!OSF_PROFILE_BEFORE_PROLOGUE) \ + { \ + char *prefix = ""; \ + char *lprefix = LPREFIX; \ + int labelno = LABELNO; \ + \ + /* Note that OSF/rose blew it in terms of calling mcount, \ + since OSF/rose prepends a leading underscore, but mcount's \ + doesn't. At present, we keep this kludge for ELF as well \ + to allow old kernels to build profiling. */ \ + \ + if (flag_pic \ + && !current_function_uses_pic_offset_table \ + && !current_function_uses_const_pool) \ + abort (); \ + \ + if (TARGET_MCOUNT && flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tcall *%smcount@GOT(%%ebx)\n", prefix); \ + } \ + \ + else if (TARGET_MCOUNT) \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall %smcount\n", prefix); \ + } \ + \ + else if (flag_pic && frame_pointer_needed) \ + { \ + fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \ + fprintf (FILE, "\tpushl %%ecx\n"); \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tmovl _mcount_ptr@GOT(%%ebx),%%eax\n"); \ + fprintf (FILE, "\tcall *(%%eax)\n"); \ + fprintf (FILE, "\tpopl %%eax\n"); \ + } \ + \ + else if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \ + fprintf (FILE, "\tpushl %%ecx\n"); \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall *_mcount_ptr\n"); \ + fprintf (FILE, "\tpopl %%eax\n"); \ + } \ + \ + else \ + abort (); \ + } \ + } \ +while (0) + +#if defined (CROSS_COMPILE) && defined (HOST_BITS_PER_INT) && defined (HOST_BITS_PER_LONG) && defined (HOST_BITS_PER_LONGLONG) +#if (HOST_BITS_PER_INT==32) && (HOST_BITS_PER_LONG==64) && (HOST_BITS_PER_LONGLONG==64) +#define REAL_ARITHMETIC +#endif +#endif diff --git a/gnu/egcs/gcc/config/i386/osf1elfgdb.h b/gnu/egcs/gcc/config/i386/osf1elfgdb.h new file mode 100644 index 00000000000..af6efa2d0de --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osf1elfgdb.h @@ -0,0 +1,7 @@ +/* Target definitions for GNU compiler for Intel 80386 running OSF/1 1.3+ + with gas and gdb. */ + +/* Use stabs instead of DWARF debug format. */ +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "i386/osf1elf.h" diff --git a/gnu/egcs/gcc/config/i386/osfelf.h b/gnu/egcs/gcc/config/i386/osfelf.h new file mode 100644 index 00000000000..381ffc26313 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osfelf.h @@ -0,0 +1,79 @@ +/* Definitions of target machine for GNU compiler. + Intel 386 (OSF/1 with ELF) version. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config/i386/osfrose.h" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ +%{mrose: -D__ROSE__ %{!pic-none: -D__SHARED__}} \ +%{!mrose: -D__ELF__ %{fpic: -D__SHARED__}} \ +%{mno-underscores: -D__NO_UNDERSCORES__} \ +%{!mrose: %{!munderscores: -D__NO_UNDERSCORES__}} \ +%{.S: %{!ansi:%{!traditional:%{!traditional-cpp:%{!ftraditional: -traditional}}}}} \ +%{.S: -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \ +%{.cc: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.cxx: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.C: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.m: -D__LANGUAGE_OBJECTIVE_C} \ +%{!.S: -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}}" + +/* Turn on -pic-extern by default for OSF/rose, -fpic for ELF. */ +#undef CC1_SPEC +#define CC1_SPEC "\ +%{gline:%{!g:%{!g0:%{!g1:%{!g2: -g1}}}}} \ +%{!melf: %{!mrose: -melf }} \ +%{!mrose: %{!munderscores: %{!mno-underscores: -mno-underscores }} \ + %{!mmcount: %{!mno-mcount: %{!mmcount-ptr: -mmcount-ptr }}}} \ +%{mrose: %{!mmcount: %{!mno-mcount: %{!mmcount-ptr: -mmcount }}} \ + %{pic-extern: -mhalf-pic } %{pic-lib: -mhalf-pic } \ + %{!pic-extern: %{!pic-lib: %{pic-none: -mno-half-pic} %{!pic-none: -mhalf-pic}}} \ + %{pic-calls: } %{pic-names*: }}" + +#undef ASM_SPEC +#define ASM_SPEC "%{v*: -v}" + +#undef LINK_SPEC +#define LINK_SPEC "%{v*: -v} \ +%{mrose: %{!noshrlib: %{pic-none: -noshrlib} %{!pic-none: -warn_nopic}} \ + %{nostdlib} %{noshrlib} %{glue}} \ +%{!mrose: %{dy} %{dn} %{glue: } \ + %{h*} %{z*} \ + %{static:-dn -Bstatic} \ + %{shared:-G -dy} \ + %{symbolic:-Bsymbolic -G -dy} \ + %{G:-G} \ + %{!dy: %{!dn: %{!static: %{!shared: %{!symbolic: \ + %{noshrlib: -dn } %{pic-none: -dn } \ + %{!noshrlib: %{!pic-none: -dy}}}}}}}}" + +#undef TARGET_VERSION_INTERNAL +#undef TARGET_VERSION + +#undef I386_VERSION +#define I386_VERSION " 80386, ELF objects" + +#define TARGET_VERSION_INTERNAL(STREAM) fputs (I386_VERSION, STREAM) +#define TARGET_VERSION TARGET_VERSION_INTERNAL (stderr) + +#undef OBJECT_FORMAT_ROSE diff --git a/gnu/egcs/gcc/config/i386/osfrose.h b/gnu/egcs/gcc/config/i386/osfrose.h new file mode 100644 index 00000000000..9ad9f952d57 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/osfrose.h @@ -0,0 +1,914 @@ +/* Definitions of target machine for GNU compiler. + Intel 386 (OSF/1 with OSF/rose) version. + Copyright (C) 1991, 1992, 1993, 1996, 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. */ + +#include "halfpic.h" +#include "i386/gstabs.h" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +#define OSF_OS + +#undef WORD_SWITCH_TAKES_ARG +#define WORD_SWITCH_TAKES_ARG(STR) \ + (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) || !strcmp (STR, "pic-names")) + +/* This defines which switch letters take arguments. On svr4, most of + the normal cases (defined in gcc.c) apply, and we also have -h* and + -z* options (for the linker). */ + +#define SWITCH_TAKES_ARG(CHAR) \ + (DEFAULT_SWITCH_TAKES_ARG(CHAR) \ + || (CHAR) == 'h' \ + || (CHAR) == 'z') + +#define MASK_HALF_PIC 010000000000 /* Mask for half-pic code */ +#define MASK_HALF_PIC_DEBUG 004000000000 /* Debug flag */ +#define MASK_ELF 002000000000 /* ELF not rose */ +#define MASK_NO_UNDERSCORES 000400000000 /* suppress leading _ */ +#define MASK_LARGE_ALIGN 000200000000 /* align to >word boundaries */ +#define MASK_NO_MCOUNT 000100000000 /* profiling uses mcount_ptr */ + +#define TARGET_HALF_PIC (target_flags & MASK_HALF_PIC) +#define TARGET_DEBUG (target_flags & MASK_HALF_PIC_DEBUG) +#define HALF_PIC_DEBUG TARGET_DEBUG +#define TARGET_ELF (target_flags & MASK_ELF) +#define TARGET_ROSE ((target_flags & MASK_ELF) == 0) +#define TARGET_UNDERSCORES ((target_flags & MASK_NO_UNDERSCORES) == 0) +#define TARGET_LARGE_ALIGN (target_flags & MASK_LARGE_ALIGN) +#define TARGET_MCOUNT ((target_flags & MASK_NO_MCOUNT) == 0) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "half-pic", MASK_HALF_PIC, "Emit half-PIC code" }, \ + { "no-half-pic", -MASK_HALF_PIC, "" } \ + { "debug-half-pic", MASK_HALF_PIC_DEBUG, 0 /* intentionally undoc */ }, \ + { "debugb", MASK_HALF_PIC_DEBUG, 0 /* intentionally undoc */ }, \ + { "elf", MASK_ELF, "Emit ELF object code" }, \ + { "rose", -MASK_ELF, "Emit ROSE object code" }, \ + { "underscores", -MASK_NO_UNDERSCORES, "Symbols have a leading underscore" }, \ + { "no-underscores", MASK_NO_UNDERSCORES, "" }, \ + { "large-align", MASK_LARGE_ALIGN, "Align to >word boundaries" }, \ + { "no-large-align", -MASK_LARGE_ALIGN, "" }, \ + { "mcount", -MASK_NO_MCOUNT, "Use mcount for profiling" }, \ + { "mcount-ptr", MASK_NO_MCOUNT, "Use mcount_ptr for profiling" }, \ + { "no-mcount", MASK_NO_MCOUNT, "" }, + +/* OSF/rose uses stabs, not dwarf. */ +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#ifndef DWARF_DEBUGGING_INFO +#define DWARF_DEBUGGING_INFO /* enable dwarf debugging for testing */ +#endif + +/* Handle #pragma weak and #pragma pack. */ + +#define HANDLE_SYSV_PRAGMA +#define SUPPORTS_WEAK TARGET_ELF + +/* Change default predefines. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ +%{!melf: -D__ROSE__ %{!pic-none: -D__SHARED__}} \ +%{melf: -D__ELF__ %{fpic: -D__SHARED__}} \ +%{mno-underscores: -D__NO_UNDERSCORES__} \ +%{melf: %{!munderscores: -D__NO_UNDERSCORES__}} \ +%{.S: %{!ansi:%{!traditional:%{!traditional-cpp:%{!ftraditional: -traditional}}}}} \ +%{.S: -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \ +%{.cc: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.cxx: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.C: -D__LANGUAGE_C_PLUS_PLUS} \ +%{.m: -D__LANGUAGE_OBJECTIVE_C} \ +%{!.S: -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}}" + +/* Turn on -pic-extern by default for OSF/rose, -fpic for ELF. */ +#undef CC1_SPEC +#define CC1_SPEC "\ +%{gline:%{!g:%{!g0:%{!g1:%{!g2: -g1}}}}} \ +%{!melf: %{!mrose: -mrose }} \ +%{melf: %{!munderscores: %{!mno-underscores: -mno-underscores }} \ + %{!mmcount: %{!mno-mcount: %{!mmcount-ptr: -mmcount-ptr }}}} \ +%{!melf: %{!munderscores: %{!mno-underscores: -munderscores }} \ + %{!mmcount: %{!mno-mcount: %{!mmcount-ptr: -mmcount }}} \ + %{pic-extern: -mhalf-pic } %{pic-lib: -mhalf-pic } \ + %{!pic-extern: %{!pic-lib: %{pic-none: -mno-half-pic} %{!pic-none: -mhalf-pic}}} \ + %{pic-calls: } %{pic-names*: }}" + +#undef ASM_SPEC +#define ASM_SPEC "%{v*: -v}" + +#undef LINK_SPEC +#define LINK_SPEC "%{v*: -v} \ +%{!melf: %{!noshrlib: %{pic-none: -noshrlib} %{!pic-none: -warn_nopic}} \ + %{nostdlib} %{noshrlib} %{glue}} \ +%{melf: %{dy} %{dn} %{glue: } \ + %{h*} %{z*} \ + %{static:-dn -Bstatic} \ + %{shared:-G -dy} \ + %{symbolic:-Bsymbolic -G -dy} \ + %{G:-G} \ + %{!dy: %{!dn: %{!static: %{!shared: %{!symbolic: \ + %{noshrlib: -dn } %{pic-none: -dn } \ + %{!noshrlib: %{!pic-none: -dy}}}}}}}}" + +#undef LIB_SPEC +#define LIB_SPEC "-lc" + +#undef LIBG_SPEC +#define LIBG_SPEC "" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" + +#undef TARGET_VERSION_INTERNAL +#undef TARGET_VERSION + +#define I386_VERSION " 80386, OSF/rose objects" + +#define TARGET_VERSION_INTERNAL(STREAM) fputs (I386_VERSION, STREAM) +#define TARGET_VERSION TARGET_VERSION_INTERNAL (stderr) + +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/usr/ccs/gcc/" + +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/usr/ccs/lib/" + +/* Specify size_t, ptrdiff_t, and wchar_t types. */ +#undef SIZE_TYPE +#undef PTRDIFF_TYPE +#undef WCHAR_TYPE +#undef WCHAR_TYPE_SIZE + +#define SIZE_TYPE "long unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_TYPE "unsigned int" +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +/* Define this macro if the system header files support C++ as well + as C. This macro inhibits the usual method of using system header + files in C++, which is to pretend that the file's contents are + enclosed in `extern "C" {...}'. */ +#define NO_IMPLICIT_EXTERN_C + +/* Turn off long double being 96 bits. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* 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. + + We override it here to allow for the new profiling code to go before + the prologue and the old mcount code to go after the prologue (and + after %ebx has been set up for ELF shared library support). */ + +#define OSF_PROFILE_BEFORE_PROLOGUE \ + (!TARGET_MCOUNT \ + && !current_function_needs_context \ + && (!flag_pic \ + || !frame_pointer_needed \ + || (!current_function_uses_pic_offset_table \ + && !current_function_uses_const_pool))) + +#undef FUNCTION_PROLOGUE +#define FUNCTION_PROLOGUE(FILE, SIZE) \ +do \ + { \ + char *prefix = (TARGET_UNDERSCORES) ? "_" : ""; \ + char *lprefix = LPREFIX; \ + int labelno = profile_label_no; \ + \ + if (profile_flag && OSF_PROFILE_BEFORE_PROLOGUE) \ + { \ + if (!flag_pic && !HALF_PIC_P ()) \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall *%s_mcount_ptr\n", prefix); \ + } \ + \ + else if (HALF_PIC_P ()) \ + { \ + rtx symref; \ + \ + HALF_PIC_EXTERNAL ("_mcount_ptr"); \ + symref = HALF_PIC_PTR (gen_rtx (SYMBOL_REF, Pmode, \ + "_mcount_ptr")); \ + \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tmovl %s%s,%%eax\n", prefix, \ + XSTR (symref, 0)); \ + fprintf (FILE, "\tcall *(%%eax)\n"); \ + } \ + \ + else \ + { \ + static int call_no = 0; \ + \ + fprintf (FILE, "\tcall %sPc%d\n", lprefix, call_no); \ + fprintf (FILE, "%sPc%d:\tpopl %%eax\n", lprefix, call_no); \ + fprintf (FILE, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%sPc%d],%%eax\n", \ + lprefix, call_no++); \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%eax),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tmovl %s_mcount_ptr@GOT(%%eax),%%eax\n", \ + prefix); \ + fprintf (FILE, "\tcall *(%%eax)\n"); \ + } \ + } \ + \ + function_prologue (FILE, SIZE); \ + } \ +while (0) + +/* A C statement or compound statement to output to FILE some assembler code to + call the profiling subroutine `mcount'. Before calling, the assembler code + must load the address of a counter variable into a register where `mcount' + expects to find the address. The name of this variable is `LP' followed by + the number LABELNO, so you would generate the name using `LP%d' in a + `fprintf'. + + The details of how the address should be passed to `mcount' are determined + by your operating system environment, not by GNU CC. To figure them out, + compile a small program for profiling using the system's installed C + compiler and look at the assembler code that results. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +do \ + { \ + if (!OSF_PROFILE_BEFORE_PROLOGUE) \ + { \ + char *prefix = (TARGET_UNDERSCORES) ? "_" : ""; \ + char *lprefix = LPREFIX; \ + int labelno = LABELNO; \ + \ + /* Note that OSF/rose blew it in terms of calling mcount, \ + since OSF/rose prepends a leading underscore, but mcount's \ + doesn't. At present, we keep this kludge for ELF as well \ + to allow old kernels to build profiling. */ \ + \ + if (flag_pic \ + && !current_function_uses_pic_offset_table \ + && !current_function_uses_const_pool) \ + abort (); \ + \ + if (TARGET_MCOUNT && flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tcall *%smcount@GOT(%%ebx)\n", prefix); \ + } \ + \ + else if (TARGET_MCOUNT && HALF_PIC_P ()) \ + { \ + rtx symdef; \ + \ + HALF_PIC_EXTERNAL ("mcount"); \ + symdef = HALF_PIC_PTR (gen_rtx (SYMBOL_REF, Pmode, "mcount")); \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall *%s%s\n", prefix, XSTR (symdef, 0)); \ + } \ + \ + else if (TARGET_MCOUNT) \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall %smcount\n", prefix); \ + } \ + \ + else if (flag_pic && frame_pointer_needed) \ + { \ + fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \ + fprintf (FILE, "\tpushl %%ecx\n"); \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + lprefix, labelno); \ + fprintf (FILE, "\tmovl _mcount_ptr@GOT(%%ebx),%%eax\n"); \ + fprintf (FILE, "\tcall *(%%eax)\n"); \ + fprintf (FILE, "\tpopl %%eax\n"); \ + } \ + \ + else if (frame_pointer_needed) \ + { \ + fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \ + fprintf (FILE, "\tpushl %%ecx\n"); \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \ + fprintf (FILE, "\tcall *_mcount_ptr\n"); \ + fprintf (FILE, "\tpopl %%eax\n"); \ + } \ + \ + else \ + abort (); \ + } \ + } \ +while (0) + +/* A C function or functions which are needed in the library to + support block profiling. When support goes into libc, undo + the #if 0. */ + +#if 0 +#undef BLOCK_PROFILING_CODE +#define BLOCK_PROFILING_CODE +#endif + +/* Prefix for internally generated assembler labels. If we aren't using + underscores, we are using prefix `.'s to identify labels that should + be ignored, as in `i386/gas.h' --karl@cs.umb.edu */ +#undef LPREFIX +#define LPREFIX ((TARGET_UNDERSCORES) ? "L" : ".L") + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*%s%s%d", (TARGET_UNDERSCORES) ? "" : ".", \ + (PREFIX), (NUMBER)) + +/* 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) \ + fprintf (FILE, "%s%s%d:\n", (TARGET_UNDERSCORES) ? "" : ".", \ + PREFIX, NUM) + +/* The prefix to add to user-visible assembler symbols. */ + +/* target_flags is not accessible by the preprocessor */ +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +/* This is how to output a reference to a user-level label named NAME. */ + +#undef ASM_OUTPUT_LABELREF +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + fprintf (FILE, "%s%s", (TARGET_UNDERSCORES) ? "_" : "", NAME) + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Output a definition */ +#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ +do \ +{ \ + fprintf ((FILE), "\t%s\t", SET_ASM_OP); \ + assemble_name (FILE, LABEL1); \ + fprintf (FILE, ","); \ + assemble_name (FILE, LABEL2); \ + fprintf (FILE, "\n"); \ + } \ +while (0) + +/* A C expression to output text to align the location counter in the + way that is desirable at a point in the code that is reached only + by jumping. + + This macro need not be defined if you don't want any special + alignment to be done at such a time. Most machine descriptions do + not currently define the macro. */ + +#undef LABEL_ALIGN_AFTER_BARRIER +#define LABEL_ALIGN_AFTER_BARRIER(LABEL) \ + ((!TARGET_LARGE_ALIGN && i386_align_jumps > 2) ? 2 : i386_align_jumps) + +/* A C expression to output text to align the location counter in the + way that is desirable at the beginning of a loop. + + This macro need not be defined if you don't want any special + alignment to be done at such a time. Most machine descriptions do + not currently define the macro. */ + +#undef LOOP_ALIGN +#define LOOP_ALIGN(LABEL) (i386_align_loops) + +/* A C statement to output to the stdio stream STREAM an assembler + command to advance the location counter to a multiple of 2 to the + POWER bytes. POWER will be a C expression of type `int'. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ + fprintf (STREAM, "\t.align\t%d\n", \ + (!TARGET_LARGE_ALIGN && (POWER) > 2) ? 2 : (POWER)) + +/* A C expression that is 1 if the RTX X is a constant which is a + valid address. On most machines, this can be defined as + `CONSTANT_P (X)', but a few machines are more restrictive in + which constant addresses are supported. + + `CONSTANT_P' accepts integer-values expressions whose values are + not explicitly known, such as `symbol_ref', `label_ref', and + `high' expressions and `const' arithmetic expressions, in + addition to `const_int' and `const_double' expressions. */ + +#define CONSTANT_ADDRESS_P_ORIG(X) \ + (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \ + || GET_CODE (X) == HIGH) + +#undef CONSTANT_ADDRESS_P +#define CONSTANT_ADDRESS_P(X) \ + ((CONSTANT_ADDRESS_P_ORIG (X)) && (!HALF_PIC_P () || !HALF_PIC_ADDRESS_P (X))) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#undef LEGITIMATE_CONSTANT_P +#define LEGITIMATE_CONSTANT_P(X) \ + (!HALF_PIC_P () \ + || GET_CODE (X) == CONST_DOUBLE \ + || GET_CODE (X) == CONST_INT \ + || !HALF_PIC_ADDRESS_P (X)) + +/* 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. */ + +#undef SUBTARGET_OVERRIDE_OPTIONS +#define SUBTARGET_OVERRIDE_OPTIONS \ +{ \ + /* \ + if (TARGET_ELF && TARGET_HALF_PIC) \ + { \ + target_flags &= ~MASK_HALF_PIC; \ + flag_pic = 1; \ + } \ + */ \ + \ + if (TARGET_ROSE && flag_pic) \ + { \ + target_flags |= MASK_HALF_PIC; \ + flag_pic = 0; \ + } \ + \ + if (TARGET_HALF_PIC) \ + half_pic_init (); \ +} + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + The macro definition, if any, is executed immediately after the + rtl for DECL has been created and stored in `DECL_RTL (DECL)'. + The value of the rtl will be a `mem' whose address is a + `symbol_ref'. + + The usual thing for this macro to do is to a flag in the + `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified + name string in the `symbol_ref' (if one bit is not enough + information). + + The best way to modify the name string is by adding text to the + beginning, with suitable punctuation to prevent any ambiguity. + Allocate the new name in `saveable_obstack'. You will have to + modify `ASM_OUTPUT_LABELREF' to remove and decode the added text + and output the name accordingly. + + You can also check the information stored in the `symbol_ref' in + the definition of `GO_IF_LEGITIMATE_ADDRESS' or + `PRINT_OPERAND_ADDRESS'. */ + +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + if (HALF_PIC_P ()) \ + HALF_PIC_ENCODE (DECL); \ + \ + else if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + } \ +while (0) + + +/* On most machines, read-only variables, constants, and jump tables + are placed in the text section. If this is not the case on your + machine, this macro should be defined to be the name of a function + (either `data_section' or a function defined in `EXTRA_SECTIONS') + that switches to the section to be used for read-only items. + + If these items should be placed in the text section, this macro + should not be defined. */ + +#if 0 +#undef READONLY_DATA_SECTION +#define READONLY_DATA_SECTION() \ +do \ + { \ + if (TARGET_ELF) \ + { \ + if (in_section != in_rodata) \ + { \ + fprintf (asm_out_file, "\t.section \"rodata\"\n"); \ + in_section = in_rodata; \ + } \ + } \ + else \ + text_section (); \ + } \ +while (0) +#endif + +/* A list of names for sections other than the standard two, which are + `in_text' and `in_data'. You need not define this macro on a + system with no other sections (that GCC needs to use). */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_rodata, in_data1 + +/* Given a decl node or constant node, choose the section to output it in + and select that section. */ + +#undef SELECT_RTX_SECTION +#define SELECT_RTX_SECTION(MODE, RTX) \ +do \ + { \ + if (MODE == Pmode && HALF_PIC_P () && HALF_PIC_ADDRESS_P (RTX)) \ + data_section (); \ + else \ + readonly_data_section (); \ + } \ +while (0) + +#undef SELECT_SECTION +#define SELECT_SECTION(DECL, RELOC) \ +{ \ + if (RELOC && HALF_PIC_P ()) \ + data_section (); \ + \ + else if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (flag_writable_strings) \ + data_section (); \ + else \ + readonly_data_section (); \ + } \ + \ + else if (TREE_CODE (DECL) != VAR_DECL) \ + readonly_data_section (); \ + \ + else if (!TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \ + || !DECL_INITIAL (DECL) \ + || (DECL_INITIAL (DECL) != error_mark_node \ + && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \ + data_section (); \ + \ + else \ + readonly_data_section (); \ +} + + +/* Define the strings used for the special svr4 .type and .size directives. + These strings generally do not vary from one system running svr4 to + another, but if a given system (e.g. m88k running svr) needs to use + different pseudo-op names for these, they may be overridden in the + file which includes this one. */ + +#define TYPE_ASM_OP ".type" +#define SIZE_ASM_OP ".size" +#define SET_ASM_OP ".set" + +/* This is how we tell the assembler that a symbol is weak. */ + +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ + +#define TYPE_OPERAND_FMT "@%s" + +/* A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the name NAME of an + initialized variable which is being defined. This macro must + output the label definition (perhaps using `ASM_OUTPUT_LABEL'). + The argument DECL is the `VAR_DECL' tree node representing the + variable. + + If this macro is not defined, then the variable name is defined + in the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */ + +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ +do \ + { \ + ASM_OUTPUT_LABEL(STREAM,NAME); \ + HALF_PIC_DECLARE (NAME); \ + if (TARGET_ELF) \ + { \ + fprintf (STREAM, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (STREAM, NAME); \ + putc (',', STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', STREAM); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (STREAM, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + } \ + } \ +while (0) + +/* Output the size directive for a decl in rest_of_decl_compilation + in the case where we did not do so before the initializer. + Once we find the error_mark_node, we know that the value of + size_directive_output was set + by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ + +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ +do { \ + char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (TARGET_ELF \ + && !flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + } while (0) + +/* This is how to declare a function name. */ + +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \ +do \ + { \ + ASM_OUTPUT_LABEL(STREAM,NAME); \ + HALF_PIC_DECLARE (NAME); \ + if (TARGET_ELF) \ + { \ + fprintf (STREAM, "\t%s\t ", TYPE_ASM_OP); \ + assemble_name (STREAM, NAME); \ + putc (',', STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', STREAM); \ + ASM_DECLARE_RESULT (STREAM, DECL_RESULT (DECL)); \ + } \ + } \ +while (0) + +/* Write the extra assembler code needed to declare a function's result. + Most svr4 assemblers don't require any special declaration of the + result value, but there are exceptions. */ + +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +/* This is how to declare the size of a function. */ + +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ +do \ + { \ + if (TARGET_ELF && !flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } \ + } \ +while (0) + +/* Attach a special .ident directive to the end of the file to identify + the version of GCC which compiled this code. The format of the + .ident string is patterned after the ones produced by native svr4 + C compilers. */ + +#define IDENT_ASM_OP ".ident" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* This says what to print at the end of the assembly file */ +#define ASM_FILE_END(STREAM) \ +do \ + { \ + if (HALF_PIC_P ()) \ + HALF_PIC_FINISH (STREAM); \ + \ + if (!flag_no_ident) \ + { \ + char *fstart = main_input_filename; \ + char *fname; \ + \ + if (!fstart) \ + fstart = "<no file>"; \ + \ + fname = fstart + strlen (fstart) - 1; \ + while (fname > fstart && *fname != '/') \ + fname--; \ + \ + if (*fname == '/') \ + fname++; \ + \ + fprintf ((STREAM), "\t%s\t\"GCC: (GNU) %s %s -O%d", \ + IDENT_ASM_OP, version_string, fname, optimize); \ + \ + if (write_symbols == PREFERRED_DEBUGGING_TYPE) \ + fprintf ((STREAM), " -g%d", (int)debug_info_level); \ + \ + else if (write_symbols == DBX_DEBUG) \ + fprintf ((STREAM), " -gstabs%d", (int)debug_info_level); \ + \ + else if (write_symbols == DWARF_DEBUG) \ + fprintf ((STREAM), " -gdwarf%d", (int)debug_info_level); \ + \ + else if (write_symbols != NO_DEBUG) \ + fprintf ((STREAM), " -g??%d", (int)debug_info_level); \ + \ + if (flag_omit_frame_pointer) \ + fprintf ((STREAM), " -fomit-frame-pointer"); \ + \ + if (flag_strength_reduce) \ + fprintf ((STREAM), " -fstrength-reduce"); \ + \ + if (flag_unroll_loops) \ + fprintf ((STREAM), " -funroll-loops"); \ + \ + if (flag_schedule_insns) \ + fprintf ((STREAM), " -fschedule-insns"); \ + \ + if (flag_schedule_insns_after_reload) \ + fprintf ((STREAM), " -fschedule-insns2"); \ + \ + if (flag_force_mem) \ + fprintf ((STREAM), " -fforce-mem"); \ + \ + if (flag_force_addr) \ + fprintf ((STREAM), " -fforce-addr"); \ + \ + if (flag_inline_functions) \ + fprintf ((STREAM), " -finline-functions"); \ + \ + if (flag_caller_saves) \ + fprintf ((STREAM), " -fcaller-saves"); \ + \ + if (flag_pic) \ + fprintf ((STREAM), (flag_pic > 1) ? " -fPIC" : " -fpic"); \ + \ + if (flag_inhibit_size_directive) \ + fprintf ((STREAM), " -finhibit-size-directive"); \ + \ + if (flag_gnu_linker) \ + fprintf ((STREAM), " -fgnu-linker"); \ + \ + if (profile_flag) \ + fprintf ((STREAM), " -p"); \ + \ + if (profile_block_flag) \ + fprintf ((STREAM), " -a"); \ + \ + if (TARGET_IEEE_FP) \ + fprintf ((STREAM), " -mieee-fp"); \ + \ + if (TARGET_HALF_PIC) \ + fprintf ((STREAM), " -mhalf-pic"); \ + \ + if (!TARGET_MOVE) \ + fprintf ((STREAM), " -mno-move"); \ + \ + if (TARGET_386) \ + fprintf ((STREAM), " -m386"); \ + \ + else if (TARGET_486) \ + fprintf ((STREAM), " -m486"); \ + \ + else \ + fprintf ((STREAM), " -munknown-machine"); \ + \ + fprintf ((STREAM), (TARGET_ELF) ? " -melf\"\n" : " -mrose\"\n"); \ + } \ + } \ +while (0) + +/* Tell collect that the object format is OSF/rose. */ +#define OBJECT_FORMAT_ROSE + +/* Tell collect where the appropriate binaries are. */ +#define REAL_NM_FILE_NAME "/usr/ccs/gcc/bfd-nm" +#define REAL_STRIP_FILE_NAME "/usr/ccs/bin/strip" + +/* Use atexit for static constructors/destructors, instead of defining + our own exit function. */ +#define HAVE_ATEXIT + +/* Define this macro meaning that gcc should find the library 'libgcc.a' + by hand, rather than passing the argument '-lgcc' to tell the linker + to do the search */ +#define LINK_LIBGCC_SPECIAL + +/* A C statement to output assembler commands which will identify the object + file as having been compile with GNU CC. We don't need or want this for + OSF1. GDB doesn't need it and kdb doesn't like it */ +#define ASM_IDENTIFY_GCC(FILE) + +/* Identify the front-end which produced this file. To keep symbol + space down, and not confuse kdb, only do this if the language is + not C. */ + +#define ASM_IDENTIFY_LANGUAGE(STREAM) \ +{ \ + if (strcmp (lang_identify (), "c") != 0) \ + output_lang_identify (STREAM); \ +} + +/* Generate calls to memcpy, etc., not bcopy, etc. */ +#define TARGET_MEM_FUNCTIONS + +/* 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 + +/* Map i386 registers to the numbers dwarf expects. Of course this is different + from what stabs expects. */ + +#define DWARF_DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* Now what stabs expects in the register. */ +#define STABS_DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 : \ + (n) == 1 ? 2 : \ + (n) == 2 ? 1 : \ + (n) == 3 ? 3 : \ + (n) == 4 ? 6 : \ + (n) == 5 ? 7 : \ + (n) == 6 ? 4 : \ + (n) == 7 ? 5 : \ + (n) + 4) + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) ((write_symbols == DWARF_DEBUG) \ + ? DWARF_DBX_REGISTER_NUMBER(n) \ + : STABS_DBX_REGISTER_NUMBER(n)) diff --git a/gnu/egcs/gcc/config/i386/perform.h b/gnu/egcs/gcc/config/i386/perform.h new file mode 100644 index 00000000000..8d6d0b71dfe --- /dev/null +++ b/gnu/egcs/gcc/config/i386/perform.h @@ -0,0 +1,98 @@ +/* Definitions for AT&T assembler syntax for the Intel 80386. + Copyright (C) 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 to be able to build libgcc.a with GCC. */ + +/* It might seem that these are not important, since gcc 2 will never + call libgcc for these functions. But programs might be linked with + code compiled by gcc 1, and then these will be used. */ + +/* The arg names used to be a and b, but `a' appears inside strings + and that confuses non-ANSI cpp. */ + +#define perform_udivsi3(arg0,arg1) \ +{ \ + register int dx asm("dx"); \ + register int ax asm("ax"); \ + \ + dx = 0; \ + ax = arg0; \ + asm ("divl %3" : "=a" (ax), "=d" (dx) : "a" (ax), "g" (arg1), "d" (dx)); \ + return ax; \ +} + +#define perform_divsi3(arg0,arg1) \ +{ \ + register int dx asm("dx"); \ + register int ax asm("ax"); \ + register int cx asm("cx"); \ + \ + ax = arg0; \ + cx = arg1; \ + asm ("cltd\n\tidivl %3" : "=a" (ax), "=&d" (dx) : "a" (ax), "c" (cx)); \ + return ax; \ +} + +#define perform_umodsi3(arg0,arg1) \ +{ \ + register int dx asm("dx"); \ + register int ax asm("ax"); \ + \ + dx = 0; \ + ax = arg0; \ + asm ("divl %3" : "=a" (ax), "=d" (dx) : "a" (ax), "g" (arg1), "d" (dx)); \ + return dx; \ +} + +#define perform_modsi3(arg0,arg1) \ +{ \ + register int dx asm("dx"); \ + register int ax asm("ax"); \ + register int cx asm("cx"); \ + \ + ax = arg0; \ + cx = arg1; \ + asm ("cltd\n\tidivl %3" : "=a" (ax), "=&d" (dx) : "a" (ax), "c" (cx)); \ + return dx; \ +} + +#define perform_fixdfsi(arg0) \ +{ \ + auto unsigned short ostatus; \ + auto unsigned short nstatus; \ + auto int ret; \ + auto double tmp; \ + \ + &ostatus; /* guarantee these land in memory */ \ + &nstatus; \ + &ret; \ + &tmp; \ + \ + asm volatile ("fnstcw %0" : "=m" (ostatus)); \ + nstatus = ostatus | 0x0c00; \ + asm volatile ("fldcw %0" : /* no outputs */ : "m" (nstatus)); \ + tmp = arg0; \ + asm volatile ("fldl %0" : /* no outputs */ : "m" (tmp)); \ + asm volatile ("fistpl %0" : "=m" (ret)); \ + asm volatile ("fldcw %0" : /* no outputs */ : "m" (ostatus)); \ + \ + return ret; \ +} + diff --git a/gnu/egcs/gcc/config/i386/ptx4-i.h b/gnu/egcs/gcc/config/i386/ptx4-i.h new file mode 100644 index 00000000000..1537b4a4cee --- /dev/null +++ b/gnu/egcs/gcc/config/i386/ptx4-i.h @@ -0,0 +1,247 @@ +/* Target definitions for GNU compiler for Intel 80386 running Dynix/ptx v4 + Copyright (C) 1996 Free Software Foundation, Inc. + + Modified from sysv4.h + Originally written by Ron Guilmette (rfg@netcom.com). + Modified by Tim Wright (timw@sequent.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 "i386/i386.h" /* Base i386 target machine definitions */ +#include "i386/att.h" /* Use the i386 AT&T assembler syntax */ +#include "ptx4.h" /* Rest of definitions (non architecture dependent) */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 Sequent Dynix/ptx Version 4)"); + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. */ + +#undef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(TYPE) \ + (TYPE_MODE (TYPE) == BLKmode) + +/* Define which macros to predefine. _SEQUENT_ is our extension. */ +/* This used to define X86, but james@bigtex.cactus.org says that + is supposed to be defined optionally by user programs--not by default. */ +#define CPP_PREDEFINES \ + "-Di386 -Dunix -D_SEQUENT_ -Asystem(unix) -Asystem(ptx4) -Acpu(i386) -Amachine(i386)" + +/* This is how to output assembly code to define a `float' constant. + We always have to use a .long pseudo-op to do this because the native + SVR4 ELF assembler is buggy and it generates incorrect values when we + try to use the .float pseudo-op instead. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long value; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value); \ + else \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value); \ + } while (0) + +/* This is how to output assembly code to define a `double' constant. + We always have to use a pair of .long pseudo-ops to do this because + the native SVR4 ELF assembler is buggy and it generates incorrect + values when we try to use the .double pseudo-op instead. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long value[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + { \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \ + } \ + else \ + { \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \ + } \ + } while (0) + + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long value[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + { \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[2]); \ + } \ + else \ + { \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[2]); \ + } \ + } while (0) + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + output_file_directive (FILE, main_input_filename); \ + fprintf (FILE, "\t.version\t\"01.01\"\n"); \ + } while (0) + +/* Define the register numbers to be used in Dwarf debugging information. + The SVR4 reference port C compiler uses the following register numbers + in its Dwarf output code: + + 0 for %eax (gnu regno = 0) + 1 for %ecx (gnu regno = 2) + 2 for %edx (gnu regno = 1) + 3 for %ebx (gnu regno = 3) + 4 for %esp (gnu regno = 7) + 5 for %ebp (gnu regno = 6) + 6 for %esi (gnu regno = 4) + 7 for %edi (gnu regno = 5) + + The following three DWARF register numbers are never generated by + the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 + believes these numbers have these meanings. + + 8 for %eip (no gnu equivalent) + 9 for %eflags (no gnu equivalent) + 10 for %trapno (no gnu equivalent) + + It is not at all clear how we should number the FP stack registers + for the x86 architecture. If the version of SDB on x86/svr4 were + a bit less brain dead with respect to floating-point then we would + have a precedent to follow with respect to DWARF register numbers + for x86 FP registers, but the SDB on x86/svr4 is so completely + broken with respect to FP registers that it is hardly worth thinking + of it as something to strive for compatibility with. + + The version of x86/svr4 SDB I have at the moment does (partially) + seem to believe that DWARF register number 11 is associated with + the x86 register %st(0), but that's about all. Higher DWARF + register numbers don't seem to be associated with anything in + particular, and even for DWARF regno 11, SDB only seems to under- + stand that it should say that a variable lives in %st(0) (when + asked via an `=' command) if we said it was in DWARF regno 11, + but SDB still prints garbage when asked for the value of the + variable in question (via a `/' command). + + (Also note that the labels SDB prints for various FP stack regs + when doing an `x' command are all wrong.) + + Note that these problems generally don't affect the native SVR4 + C compiler because it doesn't allow the use of -O with -g and + because when it is *not* optimizing, it allocates a memory + location for each floating-point variable, and the memory + location is what gets described in the DWARF AT_location + attribute for the variable in question. + + Regardless of the severe mental illness of the x86/svr4 SDB, we + do something sensible here and we use the following DWARF + register numbers. Note that these are all stack-top-relative + numbers. + + 11 for %st(0) (gnu regno = 8) + 12 for %st(1) (gnu regno = 9) + 13 for %st(2) (gnu regno = 10) + 14 for %st(3) (gnu regno = 11) + 15 for %st(4) (gnu regno = 12) + 16 for %st(5) (gnu regno = 13) + 17 for %st(6) (gnu regno = 14) + 18 for %st(7) (gnu regno = 15) +*/ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* The routine used to output sequences of byte values. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable. Note that if we find subparts of the + character sequence which end with NUL (and which are shorter than + STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ + do \ + { \ + register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ + register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register unsigned bytes_in_chunk = 0; \ + for (; _ascii_bytes < limit; _ascii_bytes++) \ + { \ + register unsigned char *p; \ + if (bytes_in_chunk >= 64) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ + continue; \ + if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + { \ + if (bytes_in_chunk > 0) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \ + _ascii_bytes = p; \ + } \ + else \ + { \ + if (bytes_in_chunk == 0) \ + fprintf ((FILE), "\t.byte\t"); \ + else \ + fputc (',', (FILE)); \ + fprintf ((FILE), "0x%02x", *_ascii_bytes); \ + bytes_in_chunk += 5; \ + } \ + } \ + if (bytes_in_chunk > 0) \ + fprintf ((FILE), "\n"); \ + } \ + while (0) + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 1 diff --git a/gnu/egcs/gcc/config/i386/rtems.h b/gnu/egcs/gcc/config/i386/rtems.h new file mode 100644 index 00000000000..60e6dc7c419 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/rtems.h @@ -0,0 +1,34 @@ +/* Definitions for rtems targeting an Intel i386 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 "i386/i386-coff.h" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -Drtems -D__rtems__ \ + -Asystem(rtems) -Acpu(i386) -Amachine(i386)" + +/* Generate calls to memcpy, memcmp and memset. */ +#ifndef TARGET_MEM_FUNCTIONS +#define TARGET_MEM_FUNCTIONS +#endif + diff --git a/gnu/egcs/gcc/config/i386/rtemself.h b/gnu/egcs/gcc/config/i386/rtemself.h new file mode 100644 index 00000000000..d9d97337aa9 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/rtemself.h @@ -0,0 +1,169 @@ +/* Definitions for Intel 386 running Linux-based GNU systems with ELF format. + Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Eric Youngdale. + Modified for stabs-in-ELF by H.J. Lu. + +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 LINUX_DEFAULT_ELF + +/* A lie, I guess, but the general idea behind linux/ELF is that we are + supposed to be outputting something that will assemble under SVr4. + This gets us pretty close. */ +#include <i386/i386.h> /* Base i386 target machine definitions */ +#include <i386/att.h> /* Use the i386 AT&T assembler syntax */ +#include <linux.h> /* some common stuff */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 RTEMS with ELF)"); + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 1 + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +/* Copy this from the svr4 specifications... */ +/* Define the register numbers to be used in Dwarf debugging information. + The SVR4 reference port C compiler uses the following register numbers + in its Dwarf output code: + 0 for %eax (gnu regno = 0) + 1 for %ecx (gnu regno = 2) + 2 for %edx (gnu regno = 1) + 3 for %ebx (gnu regno = 3) + 4 for %esp (gnu regno = 7) + 5 for %ebp (gnu regno = 6) + 6 for %esi (gnu regno = 4) + 7 for %edi (gnu regno = 5) + The following three DWARF register numbers are never generated by + the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 + believes these numbers have these meanings. + 8 for %eip (no gnu equivalent) + 9 for %eflags (no gnu equivalent) + 10 for %trapno (no gnu equivalent) + It is not at all clear how we should number the FP stack registers + for the x86 architecture. If the version of SDB on x86/svr4 were + a bit less brain dead with respect to floating-point then we would + have a precedent to follow with respect to DWARF register numbers + for x86 FP registers, but the SDB on x86/svr4 is so completely + broken with respect to FP registers that it is hardly worth thinking + of it as something to strive for compatibility with. + The version of x86/svr4 SDB I have at the moment does (partially) + seem to believe that DWARF register number 11 is associated with + the x86 register %st(0), but that's about all. Higher DWARF + register numbers don't seem to be associated with anything in + particular, and even for DWARF regno 11, SDB only seems to under- + stand that it should say that a variable lives in %st(0) (when + asked via an `=' command) if we said it was in DWARF regno 11, + but SDB still prints garbage when asked for the value of the + variable in question (via a `/' command). + (Also note that the labels SDB prints for various FP stack regs + when doing an `x' command are all wrong.) + Note that these problems generally don't affect the native SVR4 + C compiler because it doesn't allow the use of -O with -g and + because when it is *not* optimizing, it allocates a memory + location for each floating-point variable, and the memory + location is what gets described in the DWARF AT_location + attribute for the variable in question. + Regardless of the severe mental illness of the x86/svr4 SDB, we + do something sensible here and we use the following DWARF + register numbers. Note that these are all stack-top-relative + numbers. + 11 for %st(0) (gnu regno = 8) + 12 for %st(1) (gnu regno = 9) + 13 for %st(2) (gnu regno = 10) + 14 for %st(3) (gnu regno = 11) + 15 for %st(4) (gnu regno = 12) + 16 for %st(5) (gnu regno = 13) + 17 for %st(6) (gnu regno = 14) + 18 for %st(7) (gnu regno = 15) +*/ +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + { \ + fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf (FILE, "\tcall mcount\n"); \ + } \ +} + +#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 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Di386 -Drtems -D__rtems__ \ + -Asystem(rtems) -Acpu(i386) -Amachine(i386)" + +/* Get perform_* macros to build libgcc.a. */ +#include "i386/perform.h" + +/* 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) + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crt0.o%s" + +#undef ENDFILE_SPEC + diff --git a/gnu/egcs/gcc/config/i386/sco.h b/gnu/egcs/gcc/config/i386/sco.h new file mode 100644 index 00000000000..55af64128a1 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sco.h @@ -0,0 +1,117 @@ +/* Definitions for Intel 386 running SCO Unix System V. + Copyright (C) 1988, 92, 94, 95, 96, 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. */ + +/* Mostly it's like AT&T Unix System V. */ + +#include "i386/sysv3.h" + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387, ie, + (TARGET_80387 | TARGET_FLOAT_RETURNS_IN_80387) + + SCO's software emulation of a 387 fails to handle the `fucomp' + opcode. fucomp is only used when generating IEEE compliant code. + So don't make TARGET_IEEE_FP default for SCO. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) + +/* Let's guess that the SCO software FPU emulator can't handle + 80-bit XFmode insns, so don't generate them. */ +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} crtbegin.o%s" + +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +/* Library spec, including SCO international language support. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} %{scointl:libintl.a%s} -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(svr3)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{scointl:-DM_INTERNAT}" + +/* This spec is used for telling cpp whether char is signed or not. */ + +#undef SIGNED_CHAR_SPEC +#if DEFAULT_SIGNED_CHAR +#define SIGNED_CHAR_SPEC \ + "%{funsigned-char:-D__CHAR_UNSIGNED__ -D_CHAR_UNSIGNED}" +#else +#define SIGNED_CHAR_SPEC \ + "%{!fsigned-char:-D__CHAR_UNSIGNED__ -D_CHAR_UNSIGNED}" +#endif + +/* Use atexit for static destructors, instead of defining + our own exit function. */ +#define HAVE_ATEXIT + +/* Specify the size_t type. */ +#define SIZE_TYPE "unsigned int" + +#if 0 /* Not yet certain whether this is needed. */ +/* If no 387, use the general regs to return floating values, + since this system does not emulate the 80387. */ + +#undef VALUE_REGNO +#define VALUE_REGNO(MODE) \ + ((TARGET_80387 + && ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode) + ? FIRST_FLOAT_REG : 0) + +#undef HARD_REGNO_MODE_OK +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO) < 2 ? 1 \ + : (REGNO) < 4 ? 1 \ + : FP_REGNO_P (REGNO) ? ((GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ + && TARGET_80387 \ + && GET_MODE_UNIT_SIZE (MODE) <= 8) \ + : (MODE) != QImode) +#endif + +/* caller has to pop the extra argument passed to functions that return + structures. */ + +#undef RETURN_POPS_ARGS +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \ + : (TARGET_RTD \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) ? (SIZE) \ + : 0) +/* On other 386 systems, the last line looks like this: + : (aggregate_value_p (TREE_TYPE (FUNTYPE))) ? GET_MODE_SIZE (Pmode) : 0) */ + +/* Handle #pragma pack. */ +#define HANDLE_SYSV_PRAGMA diff --git a/gnu/egcs/gcc/config/i386/sco4.h b/gnu/egcs/gcc/config/i386/sco4.h new file mode 100644 index 00000000000..5d1ea471dbf --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sco4.h @@ -0,0 +1,86 @@ +/* Definitions for Intel 386 running SCO Unix System V 3.2 Version 4. + Written by Chip Salzenberg. + 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. */ + + +/* Mostly it's like earlier SCO UNIX. */ + +#include "i386/sco.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{scoxpg3:%{p:mcrt1X.o%s}%{!p:crt1X.o%s}} \ + %{!scoxpg3:\ + %{posix:%{p:mcrt1P.o%s}%{!p:crt1P.o%s}} \ + %{!posix:\ + %{ansi:%{p:mcrt1A.o%s}%{!p:crt1A.o%s}} \ + %{!ansi:%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}} \ + crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "crtend.o%s \ + %{scoxpg3:crtnX.o%s} \ + %{!scoxpg3:\ + %{posix:crtnP.o%s} \ + %{!posix:\ + %{ansi:crtnA.o%s} \ + %{!ansi:crtn.o%s}}}" + +/* Library spec. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} \ + %{scoxpg3:-lcX -lcP -lcA} \ + %{!scoxpg3:\ + %{posix:-lcP -lcA} \ + %{!posix:\ + %{ansi:-lcA} \ + %{!ansi:%{scointl:-lintl} -lc}}}" + +/* Macros, macros everywhere: + Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Asystem(svr3)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ + -D_i386 -D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \ + -D_unix -D_M_UNIX -D_M_XENIX \ + -D_M_SYS5 -D_M_SYSV -D_M_SYS3 -D_M_SYSIII \ + -D_M_COFF -D_M_BITFIELDS -D_M_WORDSWAP \ + %{scoxpg3:-D_XOPEN_SOURCE -D_STRICT_NAMES} \ + %{!scoxpg3:%{posix:-D_POSIX_SOURCE -D_STRICT_NAMES}} \ + %{!scoxpg3:%{!posix:\ + %{ansi:-D_STRICT_NAMES}%{!ansi:\ + -Di386 -DM_I386 -DM_I86 -DM_I86SM -DM_SDATA -DM_STEXT \ + -Dunix -DM_UNIX -DM_XENIX \ + -DM_SYS5 -DM_SYSV -DM_SYS3 -DM_SYSIII \ + -DM_COFF -DM_BITFIELDS -DM_WORDSWAP \ + %{scointl:-D_M_INTERNAT -DM_INTERNAT} \ + %{traditional:-D_KR -D_SVID -D_NO_PROTOTYPE}}}}" + +/* The system headers are C++-aware. */ +#define NO_IMPLICIT_EXTERN_C diff --git a/gnu/egcs/gcc/config/i386/sco4dbx.h b/gnu/egcs/gcc/config/i386/sco4dbx.h new file mode 100644 index 00000000000..3d075b6a2e2 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sco4dbx.h @@ -0,0 +1,81 @@ +/* Definitions for Intel 386 running SCO Unix System V 3.2 Version 4.s, + using dbx-in-coff encapsulation. + Copyright (C) 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Mostly it's like earlier SCO UNIX. */ + +#include "i386/scodbx.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!r:%{!z:gcc.ifile%s}%{z:gccz.ifile%s}}\ + %{scoxpg3:%{p:mcrt1X.o%s}%{!p:crt1X.o%s}} \ + %{!scoxpg3:\ + %{posix:%{p:mcrt1P.o%s}%{!p:crt1P.o%s}} \ + %{!posix:\ + %{ansi:%{p:mcrt1A.o%s}%{!p:crt1A.o%s}} \ + %{!ansi:%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{scoxpg3:crtnX.o%s} \ + %{!scoxpg3:\ + %{posix:crtnP.o%s} \ + %{!posix:\ + %{ansi:crtnA.o%s} \ + %{!ansi:crtn.o%s}}}" + +/* Library spec. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} \ + %{scoxpg3:-lcX -lcP -lcA} \ + %{!scoxpg3:\ + %{posix:-lcP -lcA} \ + %{!posix:\ + %{ansi:-lcA} \ + %{!ansi:%{scointl:-lintl} -lc}}}" + +/* Macros, macros everywhere: + Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -Asystem(svr3)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ + -D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \ + -D_M_UNIX -D_M_XENIX \ + -D_M_SYS5 -D_M_SYSV -D_M_SYS3 -D_M_SYSIII \ + -D_M_COFF -D_M_BITFIELDS -D_M_WORDSWAP \ + %{scoxpg3:-D_XOPEN_SOURCE -D_STRICT_NAMES} \ + %{!scoxpg3:%{posix:-D_POSIX_SOURCE -D_STRICT_NAMES}} \ + %{!scoxpg3:%{!posix:\ + %{ansi:-D_STRICT_NAMES}%{!ansi:\ + -DM_I386 -DM_I86 -DM_I86SM -DM_SDATA -DM_STEXT \ + -DM_UNIX -DM_XENIX \ + -DM_SYS5 -DM_SYSV -DM_SYS3 -DM_SYSIII \ + -DM_COFF -DM_BITFIELDS -DM_WORDSWAP \ + %{scointl:-D_M_INTERNAT -DM_INTERNAT} \ + %{traditional:-D_KR -D_SVID -D_NO_PROTOTYPE}}}}" diff --git a/gnu/egcs/gcc/config/i386/sco5.h b/gnu/egcs/gcc/config/i386/sco5.h new file mode 100644 index 00000000000..ac4e7e1e094 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sco5.h @@ -0,0 +1,976 @@ +/* Definitions for Intel 386 running SCO Unix System V 3.2 Version 5. + Copyright (C) 1992, 95-98, 1999 Free Software Foundation, Inc. + Contributed by Kean Johnston (hug@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 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 "i386/i386.h" /* Base i386 target definitions */ +#include "i386/att.h" /* Use AT&T i386 assembler syntax */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386, SCO OpenServer 5 Syntax)"); + +#undef LPREFIX +#define LPREFIX ".L" + +#undef ALIGN_ASM_OP +#define ALIGN_ASM_OP "\t.align" + +#undef ASCII_DATA_ASM_OP +#define ASCII_DATA_ASM_OP "\t.ascii" + +#undef ASM_BYTE_OP +#define ASM_BYTE_OP "\t.byte" + +#undef IDENT_ASM_OP +#define IDENT_ASM_OP "\t.ident" + +#undef COMMON_ASM_OP +#define COMMON_ASM_OP "\t.comm" + +#undef SET_ASM_OP +#define SET_ASM_OP "\t.set" + +#undef LOCAL_ASM_OP +#define LOCAL_ASM_OP "\t.local" + +#undef INT_ASM_OP +#define INT_ASM_OP "\t.long" + +#undef ASM_SHORT +#define ASM_SHORT "\t.value" + +#undef ASM_LONG +#define ASM_LONG "\t.long" + +#undef ASM_DOUBLE +#define ASM_DOUBLE "\t.double" + +#undef TYPE_ASM_OP +#define TYPE_ASM_OP "\t.type" + +#undef SIZE_ASM_OP +#define SIZE_ASM_OP "\t.size" + +#undef STRING_ASM_OP +#define STRING_ASM_OP "\t.string" + +#undef SKIP_ASM_OP +#define SKIP_ASM_OP "\t.zero" + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "\t.globl" + +#undef EH_FRAME_SECTION_ASM_OP +#define EH_FRAME_SECTION_ASM_OP_COFF "\t.section\t.ehfram, \"x\"" +#define EH_FRAME_SECTION_ASM_OP_ELF "\t.section\t.eh_frame, \"aw\"" +#define EH_FRAME_SECTION_ASM_OP \ + ((TARGET_ELF) ? EH_FRAME_SECTION_ASM_OP_ELF : EH_FRAME_SECTION_ASM_OP_COFF) + +/* Avoid problems (long sectino names, forward assembler refs) with DWARF + exception unwinding when we're generating COFF */ +#define DWARF2_UNWIND_INFO \ + ((TARGET_ELF) ? 1 : 0 ) + +#undef CONST_SECTION_ASM_OP +#define CONST_SECTION_ASM_OP_COFF "\t.section\t.rodata, \"x\"" +#define CONST_SECTION_ASM_OP_ELF "\t.section\t.rodata" +#define CONST_SECTION_ASM_OP \ + ((TARGET_ELF) ? CONST_SECTION_ASM_OP_ELF : CONST_SECTION_ASM_OP_COFF) + +#undef USE_CONST_SECTION +#define USE_CONST_SECTION_ELF 1 +#define USE_CONST_SECTION_COFF 0 +#define USE_CONST_SECTION \ + ((TARGET_ELF) ? USE_CONST_SECTION_ELF : USE_CONST_SECTION_COFF) + +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP_ELF "\t.section\t.init" +#define INIT_SECTION_ASM_OP_COFF "\t.section\t.init ,\"x\"" +#define INIT_SECTION_ASM_OP \ + ((TARGET_ELF) ? INIT_SECTION_ASM_OP_ELF : INIT_SECTION_ASM_OP_COFF) + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP_ELF "\t.section\t.ctors,\"aw\"" +#define CTORS_SECTION_ASM_OP_COFF INIT_SECTION_ASM_OP_COFF +#define CTORS_SECTION_ASM_OP \ + ((TARGET_ELF) ? CTORS_SECTION_ASM_OP_ELF : CTORS_SECTION_ASM_OP_COFF) + +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP_ELF "\t.section\t.dtors, \"aw\"" +#define DTORS_SECTION_ASM_OP_COFF FINI_SECTION_ASM_OP_COFF +#define DTORS_SECTION_ASM_OP \ + ((TARGET_ELF) ? DTORS_SECTION_ASM_OP_ELF : DTORS_SECTION_ASM_OP_COFF) + +#undef FINI_SECTION_ASM_OP +#define FINI_SECTION_ASM_OP_ELF "\t.section\t.fini" +#define FINI_SECTION_ASM_OP_COFF "\t.section\t.fini, \"x\"" +#define FINI_SECTION_ASM_OP \ + ((TARGET_ELF) ? FINI_SECTION_ASM_OP_ELF : FINI_SECTION_ASM_OP_COFF) + +#undef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP "\t.data" + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\t.text" + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\t.data" + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" + +#undef APPLY_RESULT_SIZE +#define APPLY_RESULT_SIZE \ +(TARGET_ELF) ? size : 116 + +#ifndef ASM_DECLARE_RESULT +#define ASM_DECLARE_RESULT(FILE, RESULT) +#endif + +#define SCO_DEFAULT_ASM_COFF(FILE,NAME) \ +do { \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } while (0) + +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do { \ + if (TARGET_ELF) { \ + fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ + putc ('\n', FILE); \ + ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } else \ + SCO_DEFAULT_ASM_COFF(FILE, NAME); \ +} while (0) + +#undef ASM_DECLARE_FUNCTION_SIZE +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do { \ + if (TARGET_ELF) { if (!flag_inhibit_size_directive) \ + { \ + fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ",.-"); \ + assemble_name (FILE, (FNAME)); \ + putc ('\n', FILE); \ + } } \ + } while (0) + +#undef ASM_DECLARE_OBJECT_NAME +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do { \ + if (TARGET_ELF) { \ + fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } else \ + SCO_DEFAULT_ASM_COFF(FILE, NAME); \ + } while (0) + +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ +do { \ + output_file_directive((FILE),main_input_filename); \ + fprintf ((FILE), "\t.version\t\"01.01\"\n"); \ +} while (0) + +#undef ASM_FILE_END +#define ASM_FILE_END(FILE) \ +do { \ + if (!flag_no_ident) \ + fprintf ((FILE), "%s\t\"GCC: (GNU) %s\"\n", \ + IDENT_ASM_OP, version_string); \ +} while (0) + +#undef ASM_FINISH_DECLARE_OBJECT +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ +do { \ + if (TARGET_ELF) { \ + char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + } \ +} while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ +do { \ + if (TARGET_ELF) \ + sprintf (LABEL, "*.%s%d", (PREFIX), (NUM)); \ + else \ + sprintf (LABEL, ".%s%d", (PREFIX), (NUM)); \ +} while (0) + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ +do { \ + if (TARGET_ELF) \ + fprintf (FILE, "%s _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", ASM_LONG, LPREFIX, VALUE); \ + else \ + fprintf (FILE, "\t.word %s%d-%s%d\n", LPREFIX,VALUE,LPREFIX,REL); \ +} while (0) + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ +do { \ + fprintf ((FILE), "%s\t", COMMON_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + if (TARGET_ELF) \ + fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ + else \ + fprintf ((FILE), ",%u\n", (SIZE)); \ +} while (0) + +#undef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ +do { \ + if (TARGET_ELF) { \ + fprintf ((FILE), "%s\t", LOCAL_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), "\n"); \ + ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \ + } else { \ + int align = exact_log2 (ALIGN); \ + if (align > 2) align = 2; \ + if (TARGET_SVR3_SHLIB) \ + data_section (); \ + else \ + bss_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + fprintf ((FILE), "%s\t", "\t.lcomm"); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%u\n", (SIZE)); \ + } \ +} while (0) + +/* 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) + +#undef ESCAPES +#define ESCAPES \ +"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\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\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\\\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\0\0\0\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" + +#undef STRING_LIMIT +#define STRING_LIMIT ((unsigned) 256) + +#undef ASM_OUTPUT_LIMITED_STRING +#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ + do \ + { \ + register unsigned char *_limited_str = (unsigned char *) (STR); \ + register unsigned ch; \ + fprintf ((FILE), "%s\t\"", STRING_ASM_OP); \ + for (; (ch = *_limited_str); _limited_str++) \ + { \ + register int escape; \ + switch (escape = ESCAPES[ch]) \ + { \ + case 0: \ + putc (ch, (FILE)); \ + break; \ + case 1: \ + fprintf ((FILE), "\\%03o", ch); \ + break; \ + default: \ + putc ('\\', (FILE)); \ + putc (escape, (FILE)); \ + break; \ + } \ + } \ + fprintf ((FILE), "\"\n"); \ + } \ + while (0) + + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ +do { \ + register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ + register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register unsigned bytes_in_chunk = 0; \ + for (; _ascii_bytes < limit; _ascii_bytes++) \ + { \ + register unsigned char *p; \ + if (bytes_in_chunk >= 64) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ + continue; \ + if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + { \ + if (bytes_in_chunk > 0) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \ + _ascii_bytes = p; \ + } \ + else \ + { \ + if (bytes_in_chunk == 0) \ + fprintf ((FILE), "%s\t", ASM_BYTE_OP); \ + else \ + fputc (',', (FILE)); \ + fprintf ((FILE), "0x%02x", *_ascii_bytes); \ + bytes_in_chunk += 5; \ + } \ + } \ + if (bytes_in_chunk > 0) \ + fprintf ((FILE), "\n"); \ +} while (0) + +/* Must use data section for relocatable constants when pic. */ +#undef SELECT_RTX_SECTION +#define SELECT_RTX_SECTION(MODE,RTX) \ +{ \ + if (TARGET_ELF) { \ + if (flag_pic && symbolic_operand (RTX)) \ + data_section (); \ + else \ + const_section (); \ + } else \ + readonly_data_section(); \ +} + +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ +do { \ + if (TARGET_ELF) \ + ASM_OUTPUT_ALIGN ((FILE), 2); \ + ASM_OUTPUT_INTERNAL_LABEL((FILE),(PREFIX),(NUM)); \ +} while (0) + + +#undef ASM_OUTPUT_CONSTRUCTOR +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ +do { \ + if (TARGET_ELF) { \ + ctors_section (); \ + fprintf (FILE, "%s\t ", INT_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } else { \ + init_section (); \ + fprintf (FILE, "\tpushl $"); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); } \ + } while (0) + +#undef ASM_OUTPUT_DESTRUCTOR +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ +do { \ + if (TARGET_ELF) { \ + dtors_section (); \ + fprintf (FILE, "%s\t ", INT_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } else { \ + fini_section (); \ + fprintf (FILE, "%s\t ", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); } \ + } while (0) + + +#undef ASM_OUTPUT_IDENT +#define ASM_OUTPUT_IDENT(FILE, NAME) \ + fprintf (FILE, "%s\t\"%s\"\n", IDENT_ASM_OP, NAME); + +#undef ASM_GLOBALIZE_LABEL +#define ASM_GLOBALIZE_LABEL(FILE,NAME) \ + (fprintf ((FILE), "%s ", GLOBAL_ASM_OP), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +#undef ASM_OUTPUT_EXTERNAL_LIBCALL +#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ + if (TARGET_ELF) ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* The prefix to add to user-visible assembler symbols. */ + +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +/* + * Compensate for the difference between ELF and COFF assembler syntax. + * Otherwise, this is cribbed from ../svr4.h. + * We rename 'gcc_except_table' to the shorter name in preparation + * for the day when we're ready to do DWARF2 eh unwinding under COFF + */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \ +do { \ + static struct section_info \ + { \ + struct section_info *next; \ + char *name; \ + enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \ + } *sections; \ + struct section_info *s; \ + char *mode; \ + enum sect_enum type; \ + char *sname = NAME ; \ + if (strcmp(NAME, ".gcc_except_table") == 0) sname = ".gccexc" ; \ + \ + for (s = sections; s; s = s->next) \ + if (!strcmp (NAME, s->name)) \ + break; \ + \ + if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \ + type = SECT_EXEC, mode = (TARGET_ELF) ? "ax" : "x" ; \ + else if (DECL && DECL_READONLY_SECTION (DECL, RELOC)) \ + type = SECT_RO, mode = "a"; \ + else \ + type = SECT_RW, mode = (TARGET_ELF) ? "aw" : "w" ; \ + \ + if (s == 0) \ + { \ + s = (struct section_info *) xmalloc (sizeof (struct section_info)); \ + s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \ + strcpy (s->name, NAME); \ + s->type = type; \ + s->next = sections; \ + sections = s; \ + fprintf (FILE, ".section\t%s,\"%s\"%s\n", sname, mode, \ + (TARGET_ELF) ? ",@progbits" : "" ); \ + } \ + else \ + { \ + if (DECL && s->type != type) \ + error_with_decl (DECL, "%s causes a section type conflict"); \ + \ + fprintf (FILE, ".section\t%s\n", sname); \ + } \ +} while (0) + +#undef ASM_OUTPUT_SKIP +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ +do { \ + if (TARGET_ELF) \ + fprintf (FILE, "%s\t%u\n", SKIP_ASM_OP, (SIZE)); \ + else \ + fprintf ((FILE), "%s\t.,.+%u\n", SET_ASM_OP, (SIZE)); \ +} while (0) + + +#undef CTOR_LIST_BEGIN +#define CTOR_LIST_BEGIN \ +do { \ + asm (CTORS_SECTION_ASM_OP); \ + if (TARGET_ELF) \ + STATIC func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) }; \ + else \ + asm ("pushl $0"); \ +} while (0) + +#undef CTOR_LIST_END +#define CTOR_LIST_END \ +do { \ + if (TARGET_ELF) { \ + asm (CTORS_SECTION_ASM_OP); \ + STATIC func_ptr __CTOR_LIST__[1] = { (func_ptr) (0) }; \ + } else { \ + CTOR_LIST_BEGIN; \ + } \ +} while (0) + +#undef DBX_BLOCKS_FUNCTION_RELATIVE +#define DBX_BLOCKS_FUNCTION_RELATIVE 1 + +#undef DBX_FUNCTION_FIRST +#define DBX_FUNCTION_FIRST 1 + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((TARGET_ELF) ? \ + ((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) \ + : \ + ((n) == 0 ? 0 : \ + (n) == 1 ? 2 : \ + (n) == 2 ? 1 : \ + (n) == 3 ? 3 : \ + (n) == 4 ? 6 : \ + (n) == 5 ? 7 : \ + (n) == 6 ? 4 : \ + (n) == 7 ? 5 : \ + (n) + 4)) + +#undef DWARF_DEBUGGING_INFO +#undef SDB_DEBUGGING_INFO +#undef DBX_DEBUGGING_INFO +#undef PREFERRED_DEBUGGING_TYPE + +#define DWARF_DEBUGGING_INFO 1 +#define SDB_DEBUGGING_INFO 1 +#define DBX_DEBUGGING_INFO 1 +#define PREFERRED_DEBUGGING_TYPE \ + ((TARGET_ELF) ? DWARF_DEBUG: SDB_DEBUG) + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_const, in_init, in_fini, in_ctors, in_dtors + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CONST_SECTION_FUNCTION \ + INIT_SECTION_FUNCTION \ + FINI_SECTION_FUNCTION \ + CTORS_SECTION_FUNCTION \ + DTORS_SECTION_FUNCTION + +#undef CONST_SECTION_FUNCTION +#define CONST_SECTION_FUNCTION \ +void \ +const_section () \ +{ \ + extern void text_section(); \ + if (!USE_CONST_SECTION) \ + text_section(); \ + else if (in_section != in_const) \ + { \ + fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \ + in_section = in_const; \ + } \ +} + +#undef FINI_SECTION_FUNCTION +#define FINI_SECTION_FUNCTION \ +void \ +fini_section () \ +{ \ + if ((!TARGET_ELF) && in_section != in_fini) \ + { \ + fprintf (asm_out_file, "%s\n", FINI_SECTION_ASM_OP); \ + in_section = in_fini; \ + } \ +} + +#undef INIT_SECTION_FUNCTION +#define INIT_SECTION_FUNCTION \ +void \ +init_section () \ +{ \ + if ((!TARGET_ELF) && in_section != in_init) \ + { \ + fprintf (asm_out_file, "%s\n", INIT_SECTION_ASM_OP); \ + in_section = in_init; \ + } \ +} + +#undef CTORS_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; \ + } \ +} + +#undef DTORS_SECTION_FUNCTION +#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; \ + } \ +} + +#undef FRAME_POINTER_REQUIRED +#define FRAME_POINTER_REQUIRED \ + ((TARGET_ELF) ? 0 : \ + (current_function_calls_setjmp || current_function_calls_longjmp)) + +#undef JUMP_TABLES_IN_TEXT_SECTION +#define JUMP_TABLES_IN_TEXT_SECTION (TARGET_ELF && flag_pic) + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX \ + ((TARGET_ELF) ? "" : ".") + +#undef MD_EXEC_PREFIX +#undef MD_STARTFILE_PREFIX +#define MD_EXEC_PREFIX "/usr/ccs/bin/" +#define MD_STARTFILE_PREFIX "/usr/ccs/lib/" + +#undef NON_SAVING_SETJMP +#define NON_SAVING_SETJMP \ + ((TARGET_ELF) ? 0 : \ + (current_function_calls_setjmp && current_function_calls_longjmp)) + +#undef NO_IMPLICIT_EXTERN_C +#define NO_IMPLICIT_EXTERN_C 1 + +/* JKJ FIXME - examine the ramifications of RETURN_IN_MEMORY and + RETURN_POPS_ARGS */ + +#undef RETURN_POPS_ARGS +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((TARGET_ELF) ? \ + (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE)) : \ + (((FUNDECL) && (TREE_CODE (FUNDECL) == IDENTIFIER_NODE)) ? 0 \ + : (TARGET_RTD \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) ? (SIZE) \ + : 0)) + +#undef SELECT_SECTION +#define SELECT_SECTION(DECL,RELOC) \ +{ \ + if (TARGET_ELF && flag_pic && RELOC) \ + data_section (); \ + else if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (! flag_writable_strings) \ + const_section (); \ + else \ + data_section (); \ + } \ + else if (TREE_CODE (DECL) == VAR_DECL) \ + { \ + if (! DECL_READONLY_SECTION (DECL, RELOC)) \ + data_section (); \ + else \ + const_section (); \ + } \ + else \ + const_section (); \ +} + +#undef SWITCH_TAKES_ARG +#define SWITCH_TAKES_ARG(CHAR) \ + (DEFAULT_SWITCH_TAKES_ARG(CHAR) \ + || (CHAR) == 'h' \ + || (CHAR) == 'R' \ + || (CHAR) == 'Y' \ + || (CHAR) == 'z') + +#undef WORD_SWITCH_TAKES_ARG +#define WORD_SWITCH_TAKES_ARG(STR) \ + (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \ + && strcmp (STR, "Tdata") && strcmp (STR, "Ttext") \ + && strcmp (STR, "Tbss")) + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS) + +#undef HANDLE_SYSV_PRAGMA +#define HANDLE_SYSV_PRAGMA 1 + +/* Though OpenServer support .weak in COFF, g++ doesn't play nice with it + * so we'll punt on it for now + */ +#define SUPPORTS_WEAK (TARGET_ELF) +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) + +#undef SCCS_DIRECTIVE +#define SCCS_DIRECTIVE 1 + +/* + * Define sizes and types + */ +#undef SIZE_TYPE +#undef PTRDIFF_TYPE +#undef WCHAR_TYPE +#undef WCHAR_TYPE_SIZE +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 96 +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_TYPE "long int" +#define WCHAR_TYPE_SIZE BITS_PER_WORD + +/* + * New for multilib support. Set the default switches for multilib, + * which is -melf. + */ +#define MULTILIB_DEFAULTS { "melf" } + + +/* Please note that these specs may look messy but they are required in + order to emulate the SCO Development system as closely as possible. + With SCO Open Server 5.0, you now get the linker and assembler free, + so that is what these specs are targeted for. These utilities are + very argument sensitive: a space in the wrong place breaks everything. + So RMS, please forgive this mess. It works. + + Parameters which can be passed to gcc, and their SCO equivalents: + GCC Parameter SCO Equivalent + -ansi -a ansi + -posix -a posix + -Xpg4 -a xpg4 + -Xpg4plus -a xpg4plus + -Xods30 -a ods30 + + As with SCO, the default is XPG4 plus mode. SCO also allows you to + specify a C dialect with -Xt, -Xa, -Xc, -Xk and -Xm. These are passed + on to the assembler and linker in the same way that the SCO compiler + does. + + SCO also allows you to compile, link and generate either ELF or COFF + binaries. With gcc, unlike the SCO compiler, the default is ELF. + Specify -mcoff to gcc to produce COFF binaries. -fpic will get the + assembler and linker to produce PIC code. +*/ + +/* Set up assembler flags for PIC and ELF compilations */ +#undef ASM_SPEC + +#if USE_GAS + /* Leave ASM_SPEC undefined so we pick up the master copy from gcc.c + * Undef MD_EXEC_PREFIX becuase we don't know where GAS is, but it's not + * likely in /usr/ccs/bin/ + */ +#undef MD_EXEC_PREFIX +#else + +#define ASM_SPEC \ + "-b %{!mcoff:elf}%{mcoff:coff \ + %{static:%e-static not valid with -mcoff} \ + %{shared:%e-shared not valid with -mcoff} \ + %{symbolic:%e-symbolic not valid with -mcoff}} \ + %{Ym,*} %{Yd,*} %{Wa,*:%*} \ + %{!mcoff:-E%{Xa:a}%{!Xa:%{Xc:c}%{!Xc:%{Xk:k}%{!Xk:%{Xt:t}%{!Xt:a}}}},%{ansi:ansi}%{!ansi:%{posix:posix}%{!posix:%{Xpg4:xpg4}%{!Xpg4:%{Xpg4plus:XPG4PLUS}%{!Xpg4plus:%{Xods30:ods30}%{!Xods30:XPG4PLUS}}}}},ELF %{Qn:} %{!Qy:-Qn}}" +#endif + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{shared: %{!mcoff: crti.o%s}} \ + %{!shared:\ + %{!symbolic: \ + %{pg:gcrt.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}} \ + %{ansi:values-Xc.o%s} \ + %{!ansi: \ + %{traditional:values-Xt.o%s} \ + %{!traditional: \ + %{Xa:values-Xa.o%s} \ + %{!Xa:%{Xc:values-Xc.o%s} \ + %{!Xc:%{Xk:values-Xk.o%s} \ + %{!Xk:%{Xt:values-Xt.o%s} \ + %{!Xt:values-Xa.o%s}}}}}} \ + %{mcoff:crtbeginS.o%s} %{!mcoff:crtbegin.o%s}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{!mcoff:crtend.o%s} \ + %{mcoff:crtendS.o%s} \ + %{pg:gcrtn.o%s}%{!pg:crtn.o%s}" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Asystem(svr3)" + +/* You are in a maze of GCC specs ... all alike */ + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ + %{fpic:%{mcoff:%e-fpic is not valid with -mcoff}} \ + %{fPIC:%{mcoff:%e-fPIC is not valid with -mcoff}} \ + -D__i386 -D__unix -D_SCO_DS=1 -D_M_I386 -D_M_XENIX -D_M_UNIX \ + %{!Xods30:-D_STRICT_NAMES} \ + %{!ansi:%{!posix:%{!Xods30:-D_SCO_XPG_VERS=4}}} \ + %{ansi:-isystem include/ansi%s -isystem /usr/include/ansi -D_STRICT_ANSI} \ + %{!ansi: \ + %{posix:-isystem include/posix%s -isystem /usr/include/posix \ + -D_POSIX_C_SOURCE=2 -D_POSIX_SOURCE=1} \ + %{!posix:%{Xpg4:-isystem include/xpg4%s -isystem /usr/include/xpg4 \ + -D_XOPEN_SOURCE=1} \ + %{!Xpg4:-D_M_I86 -D_M_I86SM -D_M_INTERNAT -D_M_SDATA -D_M_STEXT \ + -D_M_BITFIELDS -D_M_SYS5 -D_M_SYSV -D_M_SYSIII \ + -D_M_WORDSWAP -Dunix -DM_I386 -DM_UNIX -DM_XENIX \ + %{Xods30:-isystem include/ods_30_compat%s \ + -isystem /usr/include/ods_30_compat \ + -D_SCO_ODS_30 -DM_I86 -DM_I86SM -DM_SDATA -DM_STEXT \ + -DM_BITFIELDS -DM_SYS5 -DM_SYSV -DM_INTERNAT -DM_SYSIII \ + -DM_WORDSWAP}}}} \ + %{scointl:-DM_INTERNAT -D_M_INTERNAT} \ + %{traditional:-D_KR -D_SVID -D_NO_PROTOTYPE} \ + %{!mcoff:-D_SCO_ELF} \ + %{mcoff:-D_M_COFF -D_SCO_COFF} \ + %{!mcoff:%{fpic:-D__PIC__ -D__pic__} \ + %{fPIC:%{!fpic:-D__PIC__ -D__pic__}}} \ + %{Xa:-D_SCO_C_DIALECT=1} \ + %{!Xa:%{Xc:-D_SCO_C_DIALECT=3} \ + %{!Xc:%{Xk:-D_SCO_C_DIALECT=4} \ + %{!Xk:%{Xt:-D_SCO_C_DIALECT=2} \ + %{!Xt:-D_SCO_C_DIALECT=1}}}} \ + %{traditional:-traditional -D_KR -D_NO_PROTOTYPE}" + +#undef LINK_SPEC +#define LINK_SPEC \ + "-b %{!mcoff:elf}%{mcoff:coff \ + %{static:%e-static not valid with -mcoff} \ + %{shared:%e-shared not valid with -mcoff} \ + %{symbolic:%e-symbolic not valid with -mcoff} \ + %{fpic:%e-fpic not valid with -mcoff} \ + %{fPIC:%e-fPIC not valid with -mcoff}} \ + -R%{Xa:a}%{!Xa:%{Xc:c}%{!Xc:%{Xk:k}%{!Xk:%{Xt:t}%{!Xt:a}}}},%{ansi:ansi}%{!ansi:%{posix:posix}%{!posix:%{Xpg4:xpg4}%{!Xpg4:%{Xpg4plus:XPG4PLUS}%{!Xpg4plus:%{Xods30:ods30}%{!Xods30:XPG4PLUS}}}}},%{mcoff:COFF}%{!mcoff:ELF} \ + %{Wl,*%*} %{YP,*} %{YL,*} %{YU,*} \ + %{!YP,*:%{p:-YP,/usr/ccs/libp:/lib/libp:/usr/lib/libp:/usr/ccs/lib:/lib:/usr/lib} \ + %{!p:-YP,/usr/ccs/lib:/lib:/usr/lib}} \ + %{h*} %{static:-dn -Bstatic} %{shared:-G -dy %{!z*:-z text}} \ + %{symbolic:-Bsymbolic -G -dy %{!z*:-z text}} %{z*} %{R*} %{Y*} \ + %{G:-G} %{!mcoff:%{Qn:} %{!Qy:-Qn}}" + +/* The SCO COFF linker gets confused on the difference between "-ofoo" + and "-o foo". So we just always force a single space. */ + +#define SWITCHES_NEED_SPACES "o" + +/* Library spec. If we are not building a shared library, provide the + standard libraries, as per the SCO compiler. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{shared:pic/libgcc.a%s}%{!shared:%{!symbolic:-lcrypt -lgen -lc}}" + +#undef LIBGCC_SPEC +#define LIBGCC_SPEC \ + "%{!shared:-lgcc}" + +#define MASK_COFF 010000000000 /* Mask for elf generation */ +#define TARGET_COFF (target_flags & MASK_COFF) +#define TARGET_ELF (!(target_flags & MASK_COFF)) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "coff", MASK_COFF, "Generate COFF output" }, \ + { "elf", -MASK_COFF, "Generate ELF output" }, + +#define NO_DOLLAR_IN_LABEL + +/* Implicit library calls should use memcpy, not bcopy, etc. They are + faster on OpenServer libraries. */ + +#define TARGET_MEM_FUNCTIONS + +/* Biggest alignment supported by the object file format of this + machine. Use this macro to limit the alignment which can be + specified using the `__attribute__ ((aligned (N)))' construct. If + not defined, the default value is `BIGGEST_ALIGNMENT'. */ + +#define MAX_OFILE_ALIGNMENT (32768*8) + +/* +Here comes some major hackery to get the crt stuff to compile properly. +Since we can (and do) compile for both COFF and ELF environments, we +set things up accordingly, based on the pre-processor defines for ELF +and COFF. This is insane, but then I guess having one compiler with a +single back-end supporting two vastly different file format types is +a little insane too. But it is not impossible and we get a useful +compiler at the end of the day. Onward we go ... +*/ + +#if defined(CRT_BEGIN) || defined(CRT_END) || defined(IN_LIBGCC2) +# undef OBJECT_FORMAT_ELF +# undef HAVE_ATEXIT +# undef INIT_SECTION_ASM_OP +# undef FINI_SECTION_ASM_OP +# undef CTORS_SECTION_ASM_OP +# undef DTORS_SECTION_ASM_OP +# undef EH_FRAME_SECTION_ASM_OP +# undef CTOR_LIST_BEGIN +# undef CTOR_LIST_END +# undef DO_GLOBAL_CTORS_BODY + +# if defined (_SCO_ELF) +# define OBJECT_FORMAT_ELF +# define HAVE_ATEXIT 1 +# define INIT_SECTION_ASM_OP INIT_SECTION_ASM_OP_ELF +# define FINI_SECTION_ASM_OP FINI_SECTION_ASM_OP_ELF +# define DTORS_SECTION_ASM_OP DTORS_SECTION_ASM_OP_ELF +# define CTORS_SECTION_ASM_OP CTORS_SECTION_ASM_OP_ELF +# define EH_FRAME_SECTION_ASM_OP EH_FRAME_SECTION_ASM_OP_ELF +# else /* ! _SCO_ELF */ +# define INIT_SECTION_ASM_OP INIT_SECTION_ASM_OP_COFF +# define FINI_SECTION_ASM_OP FINI_SECTION_ASM_OP_COFF +# define DTORS_SECTION_ASM_OP DTORS_SECTION_ASM_OP_COFF +# define CTORS_SECTION_ASM_OP CTORS_SECTION_ASM_OP_COFF +# define EH_FRAME_SECTION_ASM_OP "" +# define CTOR_LIST_BEGIN asm (INIT_SECTION_ASM_OP); asm ("pushl $0") +# define CTOR_LIST_END CTOR_LIST_BEGIN +# define DO_GLOBAL_CTORS_BODY \ +do { \ + func_ptr *p, *beg = alloca(0); \ + for (p = beg; *p;) \ + (*p++) (); \ +} while (0) +# endif /* ! _SCO_ELF */ +#endif /* CRT_BEGIN !! CRT_END */ diff --git a/gnu/egcs/gcc/config/i386/sco5gas.h b/gnu/egcs/gcc/config/i386/sco5gas.h new file mode 100644 index 00000000000..de3e5d5570f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sco5gas.h @@ -0,0 +1,24 @@ +/* Definitions for Intel x86 running SCO OpenServer, running GNU assembler + Copyright (C) 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. */ + + +/* Just set a single flag we can test for inside of sco5.h and include it. */ + +#define USE_GAS 1 diff --git a/gnu/egcs/gcc/config/i386/scodbx.h b/gnu/egcs/gcc/config/i386/scodbx.h new file mode 100644 index 00000000000..d7d03f86326 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/scodbx.h @@ -0,0 +1,92 @@ +/* Definitions for Intel 386 running SCO Unix System V, + using dbx-in-coff encapsulation. + Copyright (C) 1992, 1995, 1996, 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. */ + +#include "i386/svr3dbx.h" + +/* Overridden defines for SCO systems from sco.h. */ + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387, ie, + (TARGET_80387 | TARGET_FLOAT_RETURNS_IN_80387) + + SCO's software emulation of a 387 fails to handle the `fucomp' + opcode. fucomp is only used when generating IEEE compliant code. + So don't make TARGET_IEEE_FP default for SCO. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!r:%{!z:svr3.ifile%s}%{z:svr3z.ifile%s}}\ + %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}" + +/* Library spec, including SCO international language support. */ + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} %{scointl:libintl.a%s} -lc" + +/* Specify predefined symbols in preprocessor. */ + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-Dunix -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(svr3)" + +#undef CPP_SPEC +#define CPP_SPEC " -Acpu(i386) -Amachine(i386) %{scointl:-DM_INTERNAT}" + +/* This spec is used for telling cpp whether char is signed or not. */ + +#undef SIGNED_CHAR_SPEC +#if DEFAULT_SIGNED_CHAR +#define SIGNED_CHAR_SPEC \ + "%{funsigned-char:-D__CHAR_UNSIGNED__ -D_CHAR_UNSIGNED}" +#else +#define SIGNED_CHAR_SPEC \ + "%{!fsigned-char:-D__CHAR_UNSIGNED__ -D_CHAR_UNSIGNED}" +#endif + +/* Use atexit for static destructors, instead of defining + our own exit function. */ +#define HAVE_ATEXIT + +/* caller has to pop the extra argument passed to functions that return + structures. */ + +#undef RETURN_POPS_ARGS +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ + ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \ + : (TARGET_RTD \ + && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ + || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \ + == void_type_node))) ? (SIZE) \ + : 0) +/* On other 386 systems, the last line looks like this: + : (aggregate_value_p (TREE_TYPE (FUNTYPE))) ? GET_MODE_SIZE (Pmode) : 0) */ + +/* Use periods rather than dollar signs in special g++ assembler names. */ + +#define NO_DOLLAR_IN_LABEL + +/* Handle #pragma pack. */ +#define HANDLE_SYSV_PRAGMA diff --git a/gnu/egcs/gcc/config/i386/seq-gas.h b/gnu/egcs/gcc/config/i386/seq-gas.h new file mode 100644 index 00000000000..796eaa24d62 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/seq-gas.h @@ -0,0 +1,46 @@ +/* Definitions for Sequent Intel 386 using GAS. + Copyright (C) 1992 Free Software Foundation, Inc. + +/* Mostly it's like a Sequent 386 without GAS. */ + +#include "i386/sequent.h" + +/* A C statement or statements which output an assembler instruction + opcode to the stdio stream STREAM. The macro-operand PTR is a + variable of type `char *' which points to the opcode name in its + "internal" form--the form that is written in the machine description. + + GAS version 1.38.1 doesn't understand the `repz' opcode mnemonic. + So use `repe' instead. */ + +#undef ASM_OUTPUT_OPCODE +#define ASM_OUTPUT_OPCODE(STREAM, PTR) \ +{ \ + if ((PTR)[0] == 'r' \ + && (PTR)[1] == 'e' \ + && (PTR)[2] == 'p') \ + { \ + if ((PTR)[3] == 'z') \ + { \ + fprintf (STREAM, "repe"); \ + (PTR) += 4; \ + } \ + else if ((PTR)[3] == 'n' && (PTR)[4] == 'z') \ + { \ + fprintf (STREAM, "repne"); \ + (PTR) += 5; \ + } \ + } \ +} + +/* Define macro used to output shift-double opcodes when the shift + count is in %cl. Some assemblers require %cl as an argument; + some don't. + + GAS requires the %cl argument, so override i386/unix.h. */ + +#undef SHIFT_DOUBLE_OMITS_COUNT +#define SHIFT_DOUBLE_OMITS_COUNT 0 + +/* Print opcodes the way that GAS expects them. */ +#define GAS_MNEMONICS 1 diff --git a/gnu/egcs/gcc/config/i386/seq-sysv3.h b/gnu/egcs/gcc/config/i386/seq-sysv3.h new file mode 100644 index 00000000000..9e8388d47d7 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/seq-sysv3.h @@ -0,0 +1,42 @@ +/* Sequent DYNIX/ptx 1.x (SVr3) */ + +#include "i386/sysv3.h" + +/* Sequent Symmetry SVr3 doesn't have crtn.o; crt1.o doesn't work + but crt0.o does. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"%{pg:gcrt0.o%s}\ + %{!pg:%{posix:%{p:mcrtp0.o%s}%{!p:crtp0.o%s}}\ + %{!posix:%{p:mcrt0.o%s}%{!p:crt0.o%s}}} crtbegin.o%s\ + %{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp}" + +#undef LIB_SPEC +#define LIB_SPEC \ +"%{posix:-lcposix}\ + %{shlib:-lc_s}\ + %{fshared-data:-lpps -lseq} -lc crtend.o%s" + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} -D_SEQUENT_=1" + +/* Although the .init section is used, it is not automatically invoked. + This because the _start() function in /lib/crt0.o never calls anything + from the .init section */ +#define INVOKE__main + +/* Assembler pseudo-op for initialized shared variables (.shdata). */ +#undef SHARED_SECTION_ASM_OP +#define SHARED_SECTION_ASM_OP ".section .shdata, \"ws\"" + +/* Assembler pseudo-op for uninitialized shared global variables (.shbss). */ +#undef ASM_OUTPUT_SHARED_COMMON +#define ASM_OUTPUT_SHARED_COMMON(FILE, NAME, SIZE, ROUNDED) \ +( fputs(".comm ", (FILE)), \ + assemble_name((FILE), (NAME)), \ + fprintf((FILE), ",%u,-3\n", (SIZE))) + +/* Assembler pseudo-op for uninitialized shared local variables (.shbss). */ +#undef SHARED_BSS_SECTION_ASM_OP +#define SHARED_BSS_SECTION_ASM_OP ".section .shbss, \"bs\"" diff --git a/gnu/egcs/gcc/config/i386/seq2-sysv3.h b/gnu/egcs/gcc/config/i386/seq2-sysv3.h new file mode 100644 index 00000000000..763c5f0adcc --- /dev/null +++ b/gnu/egcs/gcc/config/i386/seq2-sysv3.h @@ -0,0 +1,8 @@ +/* Sequent DYNIX/ptx 2.x (SVr3) */ + +#include "i386/seq-sysv3.h" + +/* Use atexit for static destructors, instead of defining + our own exit function. */ +#define HAVE_ATEXIT + diff --git a/gnu/egcs/gcc/config/i386/sequent.h b/gnu/egcs/gcc/config/i386/sequent.h new file mode 100644 index 00000000000..8613ad79e2d --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sequent.h @@ -0,0 +1,151 @@ +/* Definitions for Sequent Intel 386. + Copyright (C) 1988, 1994, 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. */ + +#include "i386/i386.h" + +/* Use the BSD assembler syntax. */ + +#include "i386/bsd.h" + +/* By default, don't use IEEE compatible arithmetic comparisons + because the assembler can't handle the fucom insn. + Return float values in the 387. */ + +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsequent -Asystem(unix) -Acpu(i386) -Amachine(i386)" + +/* Pass -Z and -ZO options to the linker. */ + +#define LINK_SPEC "%{Z*}" + +#if 0 /* Dynix 3.1 is said to accept -L. */ +/* Dynix V3.0.12 doesn't accept -L at all. */ + +#define LINK_LIBGCC_SPECIAL +#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} " + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Sequent Symmetry has size_t defined as int in /usr/include/sys/types.h */ +#define SIZE_TYPE "int" + +/* gcc order is ax, dx, cx, bx, si, di, bp, sp, st, st. + * dbx order is ax, dx, cx, st(0), st(1), bx, si, di, st(2), st(3), + * st(4), st(5), st(6), st(7), sp, bp */ + +/* ??? The right thing would be to change the ordering of the + registers to correspond to the conventions of this system, + and get rid of DBX_REGISTER_NUMBER. */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) < 3 ? (n) : (n) < 6 ? (n) + 2 \ + : (n) == 6 ? 15 : (n) == 7 ? 14 : 3) + +/* malcolmp@hydra.maths.unsw.EDU.AU says these two definitions + fix trouble in dbx. */ +#undef DBX_OUTPUT_LBRAC +#define DBX_OUTPUT_LBRAC(file,name) \ + fprintf (asmfile, "%s %d,0,%d,", ASM_STABN_OP, N_LBRAC, depth); \ + assemble_name (asmfile, buf); \ + fprintf (asmfile, "\n"); + +#undef DBX_OUTPUT_RBRAC +#define DBX_OUTPUT_RBRAC(file,name) \ + fprintf (asmfile, "%s %d,0,%d,", ASM_STABN_OP, N_RBRAC, depth); \ + assemble_name (asmfile, buf); \ + fprintf (asmfile, "\n"); + +/* Prevent anything from being allocated in the register pair cx/bx, + since that would confuse GDB. */ + +#undef HARD_REGNO_MODE_OK +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + (((REGNO) < 2 ? 1 \ + : (REGNO) < 4 ? 1 \ + : FP_REGNO_P (REGNO) ? (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ + : (MODE) != QImode) \ + && ! (REGNO == 2 && GET_MODE_UNIT_SIZE (MODE) > 4)) + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tmovl $.LP%d,%%eax\n\tcall mcount\n", (LABELNO)); + +/* Assembler pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP ".shdata" + +/* A C statement or statements which output an assembler instruction + opcode to the stdio stream STREAM. The macro-operand PTR is a + variable of type `char *' which points to the opcode name in its + "internal" form--the form that is written in the machine description. + + The Sequent assembler (identified as "Balance 8000 Assembler + 07/17/85 3.90" by "as -v") does not understand the `movs[bwl]' string + move mnemonics - it uses `smov[bwl]' instead. Change "movs" into + "smov", carefully avoiding the sign-extend opcodes. */ + +#define ASM_OUTPUT_OPCODE(STREAM, PTR) \ +{ \ + if ((PTR)[0] == 'm' \ + && (PTR)[1] == 'o' \ + && (PTR)[2] == 'v' \ + && (PTR)[3] == 's' \ + && ((PTR)[4] == 'b' || (PTR)[4] == 'w' || (PTR)[4] == 'l') \ + && ((PTR)[5] == ' ' || (PTR)[5] == '\t'|| (PTR)[5] == '\0')) \ + { \ + fprintf (STREAM, "smov"); \ + (PTR) += 4; \ + } \ +} + +/* 10-Aug-92 pes Local labels are prefixed with ".L" */ +#undef LPREFIX +#define LPREFIX ".L" + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER)\ + sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + +#undef ASM_OUTPUT_INTERNAL_LABEL +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM)\ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) + +/* The native compiler passes the address of the returned structure in eax. */ +#undef STRUCT_VALUE +#undef STRUCT_VALUE_INCOMING +#define STRUCT_VALUE_REGNUM 0 diff --git a/gnu/egcs/gcc/config/i386/sol2-c1.asm b/gnu/egcs/gcc/config/i386/sol2-c1.asm new file mode 100644 index 00000000000..d08bcbd4aec --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2-c1.asm @@ -0,0 +1,156 @@ +! crt1.s for Solaris 2, x86 + +! Copyright (C) 1993, 1998 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 takes control of the process from the kernel, as specified +! in section 3 of the System V Application Binary Interface, Intel386 +! Processor Supplement. It has been constructed from information obtained +! from the ABI, information obtained from single stepping existing +! Solaris executables through their startup code with gdb, and from +! information obtained by single stepping executables on other i386 SVR4 +! implementations. This file is the first thing linked into any executable. + + .file "crt1.s" + .ident "GNU C crt1.s" + .weak _cleanup + .weak _DYNAMIC + .text + +! Start creating the initial frame by pushing a NULL value for the return +! address of the initial frame, and mark the end of the stack frame chain +! (the innermost stack frame) with a NULL value, per page 3-32 of the ABI. +! Initialize the first stack frame pointer in %ebp (the contents of which +! are unspecified at process initialization). + + .globl _start +_start: + pushl $0x0 + pushl $0x0 + movl %esp,%ebp + +! As specified per page 3-32 of the ABI, %edx contains a function +! pointer that should be registered with atexit(), for proper +! shared object termination. Just push it onto the stack for now +! to preserve it. We want to register _cleanup() first. + + pushl %edx + +! Check to see if there is an _cleanup() function linked in, and if +! so, register it with atexit() as the last thing to be run by +! atexit(). + + movl $_cleanup,%eax + testl %eax,%eax + je .L1 + pushl $_cleanup + call atexit + addl $0x4,%esp +.L1: + +! Now check to see if we have an _DYNAMIC table, and if so then +! we need to register the function pointer previously in %edx, but +! now conveniently saved on the stack as the argument to pass to +! atexit(). + + movl $_DYNAMIC,%eax + testl %eax,%eax + je .L2 + call atexit +.L2: + +! Register _fini() with atexit(). We will take care of calling _init() +! directly. + + pushl $_fini + call atexit + +! Compute the address of the environment vector on the stack and load +! it into the global variable _environ. Currently argc is at 8 off +! the frame pointer. Fetch the argument count into %eax, scale by the +! size of each arg (4 bytes) and compute the address of the environment +! vector which is 16 bytes (the two zero words we pushed, plus argc, +! plus the null word terminating the arg vector) further up the stack, +! off the frame pointer (whew!). + + movl 8(%ebp),%eax + leal 16(%ebp,%eax,4),%edx + movl %edx,_environ + +! Push the environment vector pointer, the argument vector pointer, +! and the argument count on to the stack to set up the arguments +! for _init(), _fpstart(), and main(). Note that the environment +! vector pointer and the arg count were previously loaded into +! %edx and %eax respectively. The only new value we need to compute +! is the argument vector pointer, which is at a fixed address off +! the initial frame pointer. + + pushl %edx + leal 12(%ebp),%edx + pushl %edx + pushl %eax + +! Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and +! main(argc, argv, environ). + + call _init + call __fpstart + call main + +! Pop the argc, argv, and environ arguments off the stack, push the +! value returned from main(), and call exit(). + + addl $12,%esp + pushl %eax + call exit + +! An inline equivalent of _exit, as specified in Figure 3-26 of the ABI. + + pushl $0x0 + movl $0x1,%eax + lcall $7,$0 + +! If all else fails, just try a halt! + + hlt + .type _start,@function + .size _start,.-_start + +! A dummy profiling support routine for non-profiling executables, +! in case we link in some objects that have been compiled for profiling. + + .weak _mcount +_mcount: + ret + .type _mcount,@function + .size _mcount,.-_mcount diff --git a/gnu/egcs/gcc/config/i386/sol2-ci.asm b/gnu/egcs/gcc/config/i386/sol2-ci.asm new file mode 100644 index 00000000000..439c709ba68 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2-ci.asm @@ -0,0 +1,51 @@ +! crti.s for Solaris 2, x86. + +! Copyright (C) 1993 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 just supplies labeled starting points for the .init and .fini +! sections. It is linked in before the values-Xx.o files and also before +! crtbegin.o. + + .file "crti.s" + .ident "GNU C crti.s" + + .section .init + .globl _init + .type _init,@function +_init: + + .section .fini + .globl _fini + .type _fini,@function +_fini: diff --git a/gnu/egcs/gcc/config/i386/sol2-cn.asm b/gnu/egcs/gcc/config/i386/sol2-cn.asm new file mode 100644 index 00000000000..3f3bad93300 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2-cn.asm @@ -0,0 +1,46 @@ +! crtn.s for Solaris 2, x86. + +! Copyright (C) 1993 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 just supplies returns for the .init and .fini sections. It is +! linked in after all other files. + + .file "crtn.o" + .ident "GNU C crtn.o" + + .section .init + ret $0x0 + + .section .fini + ret $0x0 diff --git a/gnu/egcs/gcc/config/i386/sol2-gc1.asm b/gnu/egcs/gcc/config/i386/sol2-gc1.asm new file mode 100644 index 00000000000..24a1965f37e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2-gc1.asm @@ -0,0 +1,160 @@ +! gcrt1.s for Solaris 2, x86 + +! Copyright (C) 1993 Free Software Foundation, Inc. +! Written By Fred Fish, Nov 1992 +! +! 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 takes control of the process from the kernel, as specified +! in section 3 of the System V Application Binary Interface, Intel386 +! Processor Supplement. It has been constructed from information obtained +! from the ABI, information obtained from single stepping existing +! Solaris executables through their startup code with gdb, and from +! information obtained by single stepping executables on other i386 SVR4 +! implementations. This file is the first thing linked into any executable. + +! This is a modified crt1.s by J.W.Hawtin <oolon@ankh.org> 15/8/96, +! to allow program profiling, by calling monstartup on entry and _mcleanup +! on exit + + .file "gcrt1.s" + .ident "GNU C gcrt1.s" + .weak _DYNAMIC + .text + +! Start creating the initial frame by pushing a NULL value for the return +! address of the initial frame, and mark the end of the stack frame chain +! (the innermost stack frame) with a NULL value, per page 3-32 of the ABI. +! Initialize the first stack frame pointer in %ebp (the contents of which +! are unspecified at process initialization). + + .globl _start +_start: + pushl $0x0 + pushl $0x0 + movl %esp,%ebp + +! As specified per page 3-32 of the ABI, %edx contains a function +! pointer that should be registered with atexit(), for proper +! shared object termination. Just push it onto the stack for now +! to preserve it. We want to register _cleanup() first. + + pushl %edx + +! Check to see if there is an _cleanup() function linked in, and if +! so, register it with atexit() as the last thing to be run by +! atexit(). + + movl $_mcleanup,%eax + testl %eax,%eax + je .L1 + pushl $_mcleanup + call atexit + addl $0x4,%esp +.L1: + +! Now check to see if we have an _DYNAMIC table, and if so then +! we need to register the function pointer previously in %edx, but +! now conveniently saved on the stack as the argument to pass to +! atexit(). + + movl $_DYNAMIC,%eax + testl %eax,%eax + je .L2 + call atexit +.L2: + +! Register _fini() with atexit(). We will take care of calling _init() +! directly. + + pushl $_fini + call atexit + +! Start profiling + + pushl %ebp + movl %esp,%ebp + pushl $_etext + pushl $_start + call monstartup + addl $8,%esp + popl %ebp + +! Compute the address of the environment vector on the stack and load +! it into the global variable _environ. Currently argc is at 8 off +! the frame pointer. Fetch the argument count into %eax, scale by the +! size of each arg (4 bytes) and compute the address of the environment +! vector which is 16 bytes (the two zero words we pushed, plus argc, +! plus the null word terminating the arg vector) further up the stack, +! off the frame pointer (whew!). + + movl 8(%ebp),%eax + leal 16(%ebp,%eax,4),%edx + movl %edx,_environ + +! Push the environment vector pointer, the argument vector pointer, +! and the argument count on to the stack to set up the arguments +! for _init(), _fpstart(), and main(). Note that the environment +! vector pointer and the arg count were previously loaded into +! %edx and %eax respectively. The only new value we need to compute +! is the argument vector pointer, which is at a fixed address off +! the initial frame pointer. + + pushl %edx + leal 12(%ebp),%edx + pushl %edx + pushl %eax + +! Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and +! main(argc, argv, environ). + + call _init + call __fpstart + call main + +! Pop the argc, argv, and environ arguments off the stack, push the +! value returned from main(), and call exit(). + + addl $12,%esp + pushl %eax + call exit + +! An inline equivalent of _exit, as specified in Figure 3-26 of the ABI. + + pushl $0x0 + movl $0x1,%eax + lcall $7,$0 + +! If all else fails, just try a halt! + + hlt + .type _start,@function + .size _start,.-_start diff --git a/gnu/egcs/gcc/config/i386/sol2.h b/gnu/egcs/gcc/config/i386/sol2.h new file mode 100644 index 00000000000..cc5a089229f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2.h @@ -0,0 +1,98 @@ +/* Target definitions for GNU compiler for Intel 80386 running Solaris 2 + Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed 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 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 "i386/sysv4.h" + +/* The Solaris 2.0 x86 linker botches alignment of code sections. + It tries to align to a 16 byte boundary by padding with 0x00000090 + ints, rather than 0x90 bytes (nop). This generates trash in the + ".init" section since the contribution from crtbegin.o is only 7 + bytes. The linker pads it to 16 bytes with a single 0x90 byte, and + two 0x00000090 ints, which generates a segmentation violation when + executed. This macro forces the assembler to do the padding, since + it knows what it is doing. */ + +#define FORCE_INIT_SECTION_ALIGN asm (ALIGN_ASM_OP ## " 16") +#define FORCE_FINI_SECTION_ALIGN FORCE_INIT_SECTION_ALIGN + +/* Add "sun" to the list of symbols defined for SVR4. */ +#undef CPP_PREDEFINES +#define CPP_PREDEFINES \ + "-Dunix -D__svr4__ -D__SVR4 -Dsun -Asystem(svr4)" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) \ + %{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude}" + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} %{!shared:%{!symbolic:-lc}}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s %{pg:crtn.o%s}%{!pg:crtn.o%s}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{!shared: \ + %{!symbolic: \ + %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}\ + %{pg:gmon.o%s} crti.o%s \ + %{ansi:values-Xc.o%s} \ + %{!ansi: \ + %{traditional:values-Xt.o%s} \ + %{!traditional:values-Xa.o%s}} \ + crtbegin.o%s" + +/* This should be the same as in svr4.h, except with -R added. */ +#undef LINK_SPEC +#define LINK_SPEC \ + "%{h*} %{v:-V} \ + %{b} %{Wl,*:%*} \ + %{static:-dn -Bstatic} \ + %{shared:-G -dy -z text} \ + %{symbolic:-Bsymbolic -G -dy -z text} \ + %{G:-G} \ + %{YP,*} \ + %{R*} \ + %{compat-bsd: \ + %{!YP,*:%{pg:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \ + %{!pg:%{p:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \ + %{!p:-Y P,/usr/ucblib:/usr/ccs/lib:/usr/lib}}} \ + -R /usr/ucblib} \ + %{!compat-bsd: \ + %{!YP,*:%{pg:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \ + %{!pg:%{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \ + %{!p:-Y P,/usr/ccs/lib:/usr/lib}}}} \ + %{Qy:} %{!Qn:-Qy}" + +/* This defines which switch letters take arguments. + It is as in svr4.h but with -R added. */ + +#undef SWITCH_TAKES_ARG +#define SWITCH_TAKES_ARG(CHAR) \ + (DEFAULT_SWITCH_TAKES_ARG(CHAR) \ + || (CHAR) == 'R' \ + || (CHAR) == 'h' \ + || (CHAR) == 'z') + +#define STDC_0_IN_SYSTEM_HEADERS + +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." diff --git a/gnu/egcs/gcc/config/i386/sol2dbg.h b/gnu/egcs/gcc/config/i386/sol2dbg.h new file mode 100644 index 00000000000..9f95333b4b9 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sol2dbg.h @@ -0,0 +1,27 @@ +/* Target definitions for GNU compiler for Intel 80386 running Solaris + with gas and gdb. + This file is added into the directory .../gcc-2.../config/i386 + Workability without "#undef DWARF_DEBUGGING_INFO" is not tested. */ + +/* Use stabs instead of DWARF debug format. */ +#ifdef PREFERRED_DEBUGGING_TYPE +#undef PREFERRED_DEBUGGING_TYPE +#endif +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "i386/sol2.h" + +#ifdef DWARF_DEBUGGING_INFO +#undef DWARF_DEBUGGING_INFO +#endif + +/* + Changed from config/svr4.h in the following ways: + + - Added "%{V}". + - Modified "{%v:-V}" to take into account "%{V}". + - Added "-s" so that stabs are saved in the final executable. */ + +#undef ASM_SPEC +#define ASM_SPEC \ + "%{V} %{v:%{!V:-V}} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} -s" diff --git a/gnu/egcs/gcc/config/i386/sun.h b/gnu/egcs/gcc/config/i386/sun.h new file mode 100644 index 00000000000..ecc0e8294d2 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sun.h @@ -0,0 +1,83 @@ +/* Definitions for Intel 386 running SunOS 4.0. + Copyright (C) 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 "i386/i386.h" + +/* Use the Sun assembler syntax. */ + +#include "i386/sun386.h" + +/* Use crt0.o as a startup file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" + +#define LIB_SPEC "%{g:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} \ +%{g:-lg} %{sun386:}" +/* That last item is just to prevent a spurious error. */ + +#undef LINK_SPEC +#define LINK_SPEC \ + "%{!nostdlib:%{!r*:%{!e*:-e _start}}} -dc -dp %{static:-Bstatic}" + +/* Extra switches to give the assembler. */ + +#define ASM_SPEC "%{R} -i386 %{keep-local-as-symbols:-L}" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Di386 -Dsun386 -Dsun -Asystem(unix) -Asystem(bsd) -Acpu(i386) -Amachine(i386)" + +/* Allow #sccs in preprocessor. */ + +#define SCCS_DIRECTIVE + +/* Output #ident as a .ident. */ + +#define ASM_OUTPUT_IDENT(FILE, NAME) fprintf (FILE, "\t.ident \"%s\"\n", NAME); + +/* We don't want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Implicit library calls should use memcpy, not bcopy, etc. */ + +#define TARGET_MEM_FUNCTIONS + +/* Force structure alignment to the type used for a bitfield. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* This is partly guess. */ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + ((n) == 0 ? 11 : (n) == 1 ? 9 : (n) == 2 ? 10 : (n) == 3 ? 8 \ + : (n) == 4 ? 5 : (n) == 5 ? 4 : (n) == 6 ? 6 : (n)) + +/* Every debugger symbol must be in the text section. + Otherwise the assembler or the linker screws up. */ + +#define DEBUG_SYMS_TEXT diff --git a/gnu/egcs/gcc/config/i386/sun386.h b/gnu/egcs/gcc/config/i386/sun386.h new file mode 100644 index 00000000000..4302ec40841 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sun386.h @@ -0,0 +1,142 @@ +/* Definitions for Sun assembler syntax for the Intel 80386. + 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 common aspects of all 386 Unix assemblers. */ +#include "i386/unix.h" + +#define TARGET_VERSION fprintf (stderr, " (80386, Sun syntax)"); + +/* Define the syntax of instructions and addresses. */ + +/* Prefix for internally generated assembler labels. */ +#define LPREFIX ".L" + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* Assembler pseudos to introduce constants of various size. */ + +#define ASM_BYTE_OP "\t.byte" +#define ASM_SHORT "\t.value" +#define ASM_LONG "\t.long" +#define ASM_DOUBLE "\t.double" + +/* How to output an ASCII string constant. */ + +#define ASM_OUTPUT_ASCII(FILE, p, size) \ +do \ +{ int i = 0; \ + while (i < (size)) \ + { if (i%10 == 0) { if (i!=0) fprintf ((FILE), "\n"); \ + fprintf ((FILE), "%s ", ASM_BYTE_OP); } \ + else fprintf ((FILE), ","); \ + fprintf ((FILE), "0x%x", ((p)[i++] & 0377)) ;} \ + fprintf ((FILE), "\n"); \ +} while (0) + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + extern char *version_string, *language_string; \ + { \ + int len = strlen (main_input_filename); \ + char *na = main_input_filename + len; \ + char shorter[15]; \ + /* NA gets MAIN_INPUT_FILENAME sans directory names. */\ + while (na > main_input_filename) \ + { \ + if (na[-1] == '/') \ + break; \ + na--; \ + } \ + strncpy (shorter, na, 14); \ + shorter[14] = 0; \ + fprintf (FILE, "\t.file\t"); \ + output_quoted_string (FILE, shorter); \ + fprintf (FILE, "\n"); \ + } \ + fprintf (FILE, "\t.version\t\"%s %s\"\n", \ + language_string, version_string); \ + if (optimize) ASM_FILE_START_1 (FILE); \ + } while (0) + +#define ASM_FILE_START_1(FILE) fprintf (FILE, "\t.optim\n") + +/* 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) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) + +/* This is how to output an assembler line + that says to advance the location counter by SIZE bytes. */ + +#define ASM_OUTPUT_SKIP(FILE,SIZE) \ + fprintf ((FILE), "\t.set\t.,.+%u\n", (SIZE)) + +/* Output before read-only data. */ + +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP ".text" + +/* Output before writable data. */ + +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP ".data" + +/* Define the syntax of labels and symbol definitions/declarations. */ + +/* 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))) + +/* This is how to store into the string BUF + 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(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + +/* The prefix to add to user-visible assembler symbols. */ + +#define USER_LABEL_PREFIX "" + +/* This is how to output an internal numbered label where + PREFIX is the class of label and NUM is the number within the class. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ + fprintf (FILE, ".%s%d:\n", PREFIX, NUM) diff --git a/gnu/egcs/gcc/config/i386/svr3.ifile b/gnu/egcs/gcc/config/i386/svr3.ifile new file mode 100644 index 00000000000..32b3ddc2bf3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/svr3.ifile @@ -0,0 +1,48 @@ +/* + * svr3.ifile - for collectless G++ on i386 System V. + * Leaves memory configured at address 0. + * + * Install this file as $prefix/gcc-lib/TARGET/VERSION/gcc.ifile + * + * 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 includes page 0 in mapped memory. The value + * used for BLOCK should be or'd into this value. Here I'm setting BLOCK + * to 0x200 and BIND to ( 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(0x000200) BLOCK (0x200) : + { + /* plenty for room for headers */ + *(.init) + *(.text) + vfork = fork; /* I got tired of editing peoples sloppy code */ + *(.fini) + } + .stab BIND(ADDR(.text) + SIZEOF(.text)): { } + .stabstr BIND(ADDR(.stab) + SIZEOF(.stab)): { } + GROUP BIND( NEXT(0x400000) + + (ADDR(.stabstr) + (SIZEOF(.stabstr)) % 0x1000)): + { + .data : { + __CTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.ctor) + . += 4 ; /* trailing NULL */ + __DTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.dtor) + . += 4 ; /* trailing NULL */ + } + .bss : { } + } +} diff --git a/gnu/egcs/gcc/config/i386/svr3dbx.h b/gnu/egcs/gcc/config/i386/svr3dbx.h new file mode 100644 index 00000000000..36c01cc3c21 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/svr3dbx.h @@ -0,0 +1,83 @@ +/* Definitions for Intel 386 running system V, using dbx-in-coff encapsulation. + Copyright (C) 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "i386/svr3gas.h" + +/* We do not want to output SDB debugging information. */ + +#undef SDB_DEBUGGING_INFO + +/* We want to output DBX debugging information. */ + +#define DBX_DEBUGGING_INFO + +/* Compensate for botch in dbxout_init/dbxout_source_file which + unconditionally drops the first character from ltext_label_name */ + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ + sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + +/* With the current gas, .align N aligns to an N-byte boundary. + This is done to be compatible with the system assembler. + You must specify -DOTHER_ALIGN when building gas-1.38.1. */ + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE,LOG) \ + if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG)) + +/* Align labels, etc. at 4-byte boundaries. + For the 486, align to 16-byte boundary for sake of cache. */ + +#undef LABEL_ALIGN_AFTER_BARRIER +#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps) + +/* Align start of loop at 4-byte boundary. */ + +#undef LOOP_ALIGN +#define LOOP_ALIGN(LABEL) (i386_align_loops) + + +/* Additional overrides needed for dbx-in-coff gas, mostly taken from pbb.h */ + +/* 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 + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ +/* + * The loader directive file svr3.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, svr3.ifile also defines the list symbols + * __DTOR_LIST__ and __CTOR_LIST__. + */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!r:%{!z:svr3.ifile%s}%{z:svr3z.ifile%s}}\ + %{pg:gcrt1.o%s}%{!pg:%{posix:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}%{!posix:%{p:mcrt1.o%s}%{!p:crt1.o%s}}} \ + %{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp}" + +#define ENDFILE_SPEC "crtn.o%s" + +#undef LIB_SPEC +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc -lg" diff --git a/gnu/egcs/gcc/config/i386/svr3gas.h b/gnu/egcs/gcc/config/i386/svr3gas.h new file mode 100644 index 00000000000..a288b84e524 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/svr3gas.h @@ -0,0 +1,293 @@ +/* Definitions for Intel 386 running system V, using gas. + Copyright (C) 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. */ + +#include "i386/gas.h" + +/* Add stuff that normally comes from i386/sysv3.h */ + +/* longjmp may fail to restore the registers if called from the same + function that called setjmp. To compensate, the compiler avoids + putting variables in registers in functions that use both setjmp + and longjmp. */ + +#define NON_SAVING_SETJMP \ + (current_function_calls_setjmp && current_function_calls_longjmp) + +/* longjmp may fail to restore the stack pointer if the saved frame + pointer is the same as the caller's frame pointer. Requiring a frame + pointer in any function that calls setjmp or longjmp avoids this + problem, unless setjmp and longjmp are called from the same function. + Since a frame pointer will be required in such a function, it is OK + that the stack pointer is not restored. */ + +#undef FRAME_POINTER_REQUIRED +#define FRAME_POINTER_REQUIRED \ + (current_function_calls_setjmp || current_function_calls_longjmp) + +/* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib, adapted to gas */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + if (align > 2) align = 2; \ + if (TARGET_SVR3_SHLIB) \ + { \ + data_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED)); \ + } \ + else \ + { \ + fputs (".lcomm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%u\n", (ROUNDED)); \ + } \ + } while (0) + +/* Add stuff that normally comes from i386/sysv3.h via svr3.h */ + +/* Define the actual types of some ANSI-mandated types. These + definitions should work for most SVR3 systems. */ + +#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 + +/* ??? This stuff is copied from config/svr3.h. In the future, + this file should be rewritten to include config/svr3.h + and override what isn't right. */ + +/* Support const sections and the ctors and dtors sections for g++. + Note that there appears to be two different ways to support const + sections at the moment. You can either #define the symbol + READONLY_DATA_SECTION (giving it some code which switches to the + readonly data section) or else you can #define the symbols + EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and + SELECT_RTX_SECTION. We do both here just to be on the safe side. + However, use of the const section is turned off by default + unless the specific tm.h file turns it on by defining + USE_CONST_SECTION as 1. */ + +/* 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). + + Define ASM_OUTPUT_CONSTRUCTOR to push the address of the constructor. */ + +#define USE_CONST_SECTION 0 + +#define INIT_SECTION_ASM_OP ".section\t.init" +#define FINI_SECTION_ASM_OP ".section .fini,\"x\"" +#define CONST_SECTION_ASM_OP ".section\t.rodata, \"x\"" +#define CTORS_SECTION_ASM_OP INIT_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP FINI_SECTION_ASM_OP + +/* CTOR_LIST_BEGIN and CTOR_LIST_END are machine-dependent + because they push on the stack. */ + +#ifdef STACK_GROWS_DOWNWARD + +/* Constructor list on stack is in reverse order. Go to the end of the + list and go backwards to call constructors in the right order. */ +#define DO_GLOBAL_CTORS_BODY \ +do { \ + func_ptr *p, *beg = alloca (0); \ + for (p = beg; *p; p++) \ + ; \ + while (p != beg) \ + (*--p) (); \ +} while (0) + +#else + +/* Constructor list on stack is in correct order. Just call them. */ +#define DO_GLOBAL_CTORS_BODY \ +do { \ + func_ptr *p, *beg = alloca (0); \ + for (p = beg; *p; ) \ + (*p++) (); \ +} while (0) + +#endif /* STACK_GROWS_DOWNWARD */ + +/* Add extra sections .rodata, .init and .fini. */ + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_const, in_init, in_fini + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CONST_SECTION_FUNCTION \ + INIT_SECTION_FUNCTION \ + FINI_SECTION_FUNCTION + +#define INIT_SECTION_FUNCTION \ +void \ +init_section () \ +{ \ + if (in_section != in_init) \ + { \ + fprintf (asm_out_file, "\t%s\n", INIT_SECTION_ASM_OP); \ + in_section = in_init; \ + } \ +} + +#define FINI_SECTION_FUNCTION \ +void \ +fini_section () \ +{ \ + if (in_section != in_fini) \ + { \ + fprintf (asm_out_file, "\t%s\n", FINI_SECTION_ASM_OP); \ + in_section = in_fini; \ + } \ +} + +#define READONLY_DATA_SECTION() const_section () + +#define CONST_SECTION_FUNCTION \ +void \ +const_section () \ +{ \ + extern void text_section(); \ + if (!USE_CONST_SECTION) \ + text_section(); \ + else if (in_section != in_const) \ + { \ + fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \ + in_section = in_const; \ + } \ +} + +/* The ctors and dtors sections are not normally put into use + by EXTRA_SECTIONS and EXTRA_SECTION_FUNCTIONS as defined in svr3.h, + but it can't hurt to define these macros for whatever systems use them. */ +#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; \ + } \ +} + +/* This is machine-dependent + because it needs to push something on the stack. */ +#undef ASM_OUTPUT_CONSTRUCTOR + +/* A C statement (sans semicolon) to output an element in the table of + global destructors. */ +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + fini_section (); \ + fprintf (FILE, "%s\t ", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* A C statement or statements to switch to the appropriate + section for output of DECL. DECL is either a `VAR_DECL' node + or a constant of some sort. RELOC indicates whether forming + the initial value of DECL requires link-time relocations. */ + +#define SELECT_SECTION(DECL,RELOC) \ +{ \ + if (TREE_CODE (DECL) == STRING_CST) \ + { \ + if (! flag_writable_strings) \ + const_section (); \ + else \ + data_section (); \ + } \ + else if (TREE_CODE (DECL) == VAR_DECL) \ + { \ + if ((0 && RELOC) /* should be (flag_pic && RELOC) */ \ + || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \ + || !DECL_INITIAL (DECL) \ + || (DECL_INITIAL (DECL) != error_mark_node \ + && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \ + data_section (); \ + else \ + const_section (); \ + } \ + else \ + const_section (); \ +} + +/* A C statement or statements to switch to the appropriate + section for output of RTX in mode MODE. RTX is some kind + of constant in RTL. The argument MODE is redundant except + in the case of a `const_int' rtx. Currently, these always + go into the const section. */ + +#define SELECT_RTX_SECTION(MODE,RTX) const_section() + +/* This is copied from i386/sysv3.h. */ + +/* 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. */ + +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP ".section .init,\"x\"" + +#define CTOR_LIST_BEGIN \ + asm (INIT_SECTION_ASM_OP); \ + asm ("pushl $0") +#define CTOR_LIST_END CTOR_LIST_BEGIN + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + init_section (); \ + fprintf (FILE, "\tpushl $"); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) diff --git a/gnu/egcs/gcc/config/i386/svr3z.ifile b/gnu/egcs/gcc/config/i386/svr3z.ifile new file mode 100644 index 00000000000..4946051235e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/svr3z.ifile @@ -0,0 +1,48 @@ +/* + * svr3z.ifile - for collectless G++ on i386 System V. + * Leaves memory unconfigured at address 0. + * + * Install this file as $prefix/gcc-lib/TARGET/VERSION/gccz.ifile + * + * 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 ( 0x400000 | 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(0x400200) BLOCK (0x200) : + { + /* plenty for room for headers */ + *(.init) + *(.text) + vfork = fork; /* I got tired of editing peoples sloppy code */ + *(.fini) + } + .stab BIND(ADDR(.text) + SIZEOF(.text)): { } + .stabstr BIND(ADDR(.stab) + SIZEOF(.stab)): { } + GROUP BIND( NEXT(0x400000) + + (ADDR(.stabstr) + (SIZEOF(.stabstr)) % 0x1000)): + { + .data : { + __CTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.ctor) + . += 4 ; /* trailing NULL */ + __DTOR_LIST__ = . ; + . += 4 ; /* leading NULL */ + *(.dtor) + . += 4 ; /* trailing NULL */ + } + .bss : { } + } +} diff --git a/gnu/egcs/gcc/config/i386/sysv3.h b/gnu/egcs/gcc/config/i386/sysv3.h new file mode 100644 index 00000000000..ce898899011 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sysv3.h @@ -0,0 +1,124 @@ +/* Definitions for Intel 386 running system V. + 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 "i386/i386.h" + +/* Use default settings for system V.3. */ + +#include "svr3.h" + +/* Use the ATT assembler syntax. + This overrides at least one macro (USER_LABEL_PREFIX) from svr3.h. */ + +#include "i386/att.h" + +/* Use crt1.o as a startup file and crtn.o as a closing file. */ + +#define STARTFILE_SPEC \ + "%{pg:gcrt1.o%s}%{!pg:%{posix:%{p:mcrtp1.o%s}%{!p:crtp1.o%s}}%{!posix:%{p:mcrt1.o%s}%{!p:crt1.o%s}}} crtbegin.o%s\ + %{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp}" + +/* ??? There is a suggestion that -lg is needed here. + Does anyone know whether this is right? */ +#define LIB_SPEC "%{posix:-lcposix} %{shlib:-lc_s} -lc crtend.o%s crtn.o%s" + +/* Specify predefined symbols in preprocessor. */ + +#define CPP_PREDEFINES "-Dunix -Asystem(svr3)" + +#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE}" + +/* Writing `int' for a bitfield forces int alignment for the structure. */ + +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Don't write a `.optim' pseudo; this assembler doesn't handle them. */ + +#undef ASM_FILE_START_1 +#define ASM_FILE_START_1(FILE) + +/* We want to be able to get DBX debugging information via -gstabs. */ + +#undef DBX_DEBUGGING_INFO +#define DBX_DEBUGGING_INFO + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG + +/* longjmp may fail to restore the registers if called from the same + function that called setjmp. To compensate, the compiler avoids + putting variables in registers in functions that use both setjmp + and longjmp. */ + +#define NON_SAVING_SETJMP \ + (current_function_calls_setjmp && current_function_calls_longjmp) + +/* longjmp may fail to restore the stack pointer if the saved frame + pointer is the same as the caller's frame pointer. Requiring a frame + pointer in any function that calls setjmp or longjmp avoids this + problem, unless setjmp and longjmp are called from the same function. + Since a frame pointer will be required in such a function, it is OK + that the stack pointer is not restored. */ + +#undef FRAME_POINTER_REQUIRED +#define FRAME_POINTER_REQUIRED \ + (current_function_calls_setjmp || current_function_calls_longjmp) + +/* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib. */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + if (align > 2) align = 2; \ + if (TARGET_SVR3_SHLIB) \ + data_section (); \ + else \ + bss_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED)); \ + } while (0) + +/* 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. */ + +#undef INIT_SECTION_ASM_OP +#define INIT_SECTION_ASM_OP ".section .init,\"x\"" + +#define CTOR_LIST_BEGIN \ + asm (INIT_SECTION_ASM_OP); \ + asm ("pushl $0") +#define CTOR_LIST_END CTOR_LIST_BEGIN + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + init_section (); \ + fprintf (FILE, "\tpushl $"); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) diff --git a/gnu/egcs/gcc/config/i386/sysv4.h b/gnu/egcs/gcc/config/i386/sysv4.h new file mode 100644 index 00000000000..e688f7b8c9f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sysv4.h @@ -0,0 +1,253 @@ +/* Target definitions for GNU compiler for Intel 80386 running System V.4 + Copyright (C) 1991 Free Software Foundation, Inc. + + Written by Ron Guilmette (rfg@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 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 "i386/i386.h" /* Base i386 target machine definitions */ +#include "i386/att.h" /* Use the i386 AT&T assembler syntax */ +#include "svr4.h" /* Definitions common to all SVR4 targets */ + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 System V Release 4)"); + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. */ + +#undef RETURN_IN_MEMORY +#define RETURN_IN_MEMORY(TYPE) \ + (TYPE_MODE (TYPE) == BLKmode) + +/* Define which macros to predefine. __svr4__ is our extension. */ +/* This used to define X86, but james@bigtex.cactus.org says that + is supposed to be defined optionally by user programs--not by default. */ +#define CPP_PREDEFINES \ + "-Di386 -Dunix -D__svr4__ -Asystem(unix) -Asystem(svr4) -Acpu(i386) -Amachine(i386)" + +/* This is how to output assembly code to define a `float' constant. + We always have to use a .long pseudo-op to do this because the native + SVR4 ELF assembler is buggy and it generates incorrect values when we + try to use the .float pseudo-op instead. */ + +#undef ASM_OUTPUT_FLOAT +#define ASM_OUTPUT_FLOAT(FILE,VALUE) \ +do { long value; \ + REAL_VALUE_TO_TARGET_SINGLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value); \ + else \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value); \ + } while (0) + +/* This is how to output assembly code to define a `double' constant. + We always have to use a pair of .long pseudo-ops to do this because + the native SVR4 ELF assembler is buggy and it generates incorrect + values when we try to use the .double pseudo-op instead. */ + +#undef ASM_OUTPUT_DOUBLE +#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \ +do { long value[2]; \ + REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + { \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \ + } \ + else \ + { \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \ + } \ + } while (0) + + +#undef ASM_OUTPUT_LONG_DOUBLE +#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \ +do { long value[3]; \ + REAL_VALUE_TO_TARGET_LONG_DOUBLE ((VALUE), value); \ + if (sizeof (int) == sizeof (long)) \ + { \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \ + fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[2]); \ + } \ + else \ + { \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \ + fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[2]); \ + } \ + } while (0) + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ + +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + output_file_directive (FILE, main_input_filename); \ + fprintf (FILE, "\t.version\t\"01.01\"\n"); \ + } while (0) + +/* Define the register numbers to be used in Dwarf debugging information. + The SVR4 reference port C compiler uses the following register numbers + in its Dwarf output code: + + 0 for %eax (gnu regno = 0) + 1 for %ecx (gnu regno = 2) + 2 for %edx (gnu regno = 1) + 3 for %ebx (gnu regno = 3) + 4 for %esp (gnu regno = 7) + 5 for %ebp (gnu regno = 6) + 6 for %esi (gnu regno = 4) + 7 for %edi (gnu regno = 5) + + The following three DWARF register numbers are never generated by + the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4 + believes these numbers have these meanings. + + 8 for %eip (no gnu equivalent) + 9 for %eflags (no gnu equivalent) + 10 for %trapno (no gnu equivalent) + + It is not at all clear how we should number the FP stack registers + for the x86 architecture. If the version of SDB on x86/svr4 were + a bit less brain dead with respect to floating-point then we would + have a precedent to follow with respect to DWARF register numbers + for x86 FP registers, but the SDB on x86/svr4 is so completely + broken with respect to FP registers that it is hardly worth thinking + of it as something to strive for compatibility with. + + The version of x86/svr4 SDB I have at the moment does (partially) + seem to believe that DWARF register number 11 is associated with + the x86 register %st(0), but that's about all. Higher DWARF + register numbers don't seem to be associated with anything in + particular, and even for DWARF regno 11, SDB only seems to under- + stand that it should say that a variable lives in %st(0) (when + asked via an `=' command) if we said it was in DWARF regno 11, + but SDB still prints garbage when asked for the value of the + variable in question (via a `/' command). + + (Also note that the labels SDB prints for various FP stack regs + when doing an `x' command are all wrong.) + + Note that these problems generally don't affect the native SVR4 + C compiler because it doesn't allow the use of -O with -g and + because when it is *not* optimizing, it allocates a memory + location for each floating-point variable, and the memory + location is what gets described in the DWARF AT_location + attribute for the variable in question. + + Regardless of the severe mental illness of the x86/svr4 SDB, we + do something sensible here and we use the following DWARF + register numbers. Note that these are all stack-top-relative + numbers. + + 11 for %st(0) (gnu regno = 8) + 12 for %st(1) (gnu regno = 9) + 13 for %st(2) (gnu regno = 10) + 14 for %st(3) (gnu regno = 11) + 15 for %st(4) (gnu regno = 12) + 16 for %st(5) (gnu regno = 13) + 17 for %st(6) (gnu regno = 14) + 18 for %st(7) (gnu regno = 15) +*/ + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ +((n) == 0 ? 0 \ + : (n) == 1 ? 2 \ + : (n) == 2 ? 1 \ + : (n) == 3 ? 3 \ + : (n) == 4 ? 6 \ + : (n) == 5 ? 7 \ + : (n) == 6 ? 5 \ + : (n) == 7 ? 4 \ + : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \ + : (-1)) + +/* The routine used to output sequences of byte values. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable. Note that if we find subparts of the + character sequence which end with NUL (and which are shorter than + STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ + +#undef ASM_OUTPUT_ASCII +#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ + do \ + { \ + register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ + register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register unsigned bytes_in_chunk = 0; \ + for (; _ascii_bytes < limit; _ascii_bytes++) \ + { \ + register unsigned char *p; \ + if (bytes_in_chunk >= 64) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ + continue; \ + if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + { \ + if (bytes_in_chunk > 0) \ + { \ + fputc ('\n', (FILE)); \ + bytes_in_chunk = 0; \ + } \ + ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \ + _ascii_bytes = p; \ + } \ + else \ + { \ + if (bytes_in_chunk == 0) \ + fprintf ((FILE), "\t.byte\t"); \ + else \ + fputc (',', (FILE)); \ + fprintf ((FILE), "0x%02x", *_ascii_bytes); \ + bytes_in_chunk += 5; \ + } \ + } \ + if (bytes_in_chunk > 0) \ + fprintf ((FILE), "\n"); \ + } \ + while (0) + +/* This is how to output an element of a case-vector that is relative. + This is only used for PIC code. See comments by the `casesi' insn in + i386.md for an explanation of the expression this outputs. */ + +#undef ASM_OUTPUT_ADDR_DIFF_ELT +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE) + +/* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +/* 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) diff --git a/gnu/egcs/gcc/config/i386/sysv5.h b/gnu/egcs/gcc/config/i386/sysv5.h new file mode 100644 index 00000000000..09a3bbefc0c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/sysv5.h @@ -0,0 +1,35 @@ +/* Definitions for Intel 386 running System V Release 5 (i.e. UnixWare 7) + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Robert Lipe (robertlipe@usa.net) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "i386/sysv4.h" + +/* Dwarf2 is supported by native debuggers */ + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* Add -lcrt for Dwarf2 abbreviation table */ +#undef LIB_SPEC +#define LIB_SPEC "%{pthread:-lthread} %{!shared:%{!symbolic:-lc -lcrt}}" + +#undef CPP_SPEC +#define CPP_SPEC "%{pthread:-D_REENTRANT}" diff --git a/gnu/egcs/gcc/config/i386/t-crtpic b/gnu/egcs/gcc/config/i386/t-crtpic new file mode 100644 index 00000000000..ff81a9bef9c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-crtpic @@ -0,0 +1,10 @@ +# The pushl in CTOR initialization interferes with frame pointer elimination. + +# We need to use -fPIC when we are using gcc to compile the routines in +# crtstuff.c. This is only really needed when we are going to use gcc/g++ +# to produce a shared library, but since we don't know ahead of time when +# we will be doing that, we just always use -fPIC when compiling the +# routines in crtstuff.c. + +CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer +TARGET_LIBGCC2_CFLAGS = -fPIC diff --git a/gnu/egcs/gcc/config/i386/t-crtstuff b/gnu/egcs/gcc/config/i386/t-crtstuff new file mode 100644 index 00000000000..a202df6653f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-crtstuff @@ -0,0 +1,2 @@ +# The pushl in CTOR initialization interferes with frame pointer elimination. +CRTSTUFF_T_CFLAGS = -fno-omit-frame-pointer diff --git a/gnu/egcs/gcc/config/i386/t-cygwin b/gnu/egcs/gcc/config/i386/t-cygwin new file mode 100644 index 00000000000..175f66be6f3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-cygwin @@ -0,0 +1,16 @@ +LIBGCC1 = libgcc1-asm.a +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = i386/cygwin.asm +LIB1ASMFUNCS = _chkstk + +# cygwin always has a limits.h, but, depending upon how we are doing +# the build, it may not be installed yet. +LIMITS_H_TEST = true + +# If we are building next to winsup, this will let us find the real +# limits.h when building libgcc2. Otherwise, winsup must be installed +# first. +LIBGCC2_INCLUDES = -I$(srcdir)/../winsup/include + +winnt.o: $(srcdir)/config/i386/winnt.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/winnt.c diff --git a/gnu/egcs/gcc/config/i386/t-dgux b/gnu/egcs/gcc/config/i386/t-dgux new file mode 100644 index 00000000000..292331f22a9 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-dgux @@ -0,0 +1,4 @@ +# +# target makefile for dgux +# +EXTRA_PARTS=crtbegin.o crtend.o diff --git a/gnu/egcs/gcc/config/i386/t-djgpp b/gnu/egcs/gcc/config/i386/t-djgpp new file mode 100644 index 00000000000..6160b7ec945 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-djgpp @@ -0,0 +1,2 @@ +LIBGCC1 = libgcc1.null +CROSS_LIBGCC1 = libgcc1.null diff --git a/gnu/egcs/gcc/config/i386/t-freebsd b/gnu/egcs/gcc/config/i386/t-freebsd new file mode 100644 index 00000000000..5164669d1ac --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-freebsd @@ -0,0 +1,5 @@ +# Don't run fixproto +STMP_FIXPROTO = +# Use only native include files +USER_H = $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) + diff --git a/gnu/egcs/gcc/config/i386/t-i386bare b/gnu/egcs/gcc/config/i386/t-i386bare new file mode 100644 index 00000000000..2970fa71415 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-i386bare @@ -0,0 +1,3 @@ +# The i386 md has all of these taken care of, according to sef. +LIBGCC1 = +CROSS_LIBGCC1 = diff --git a/gnu/egcs/gcc/config/i386/t-interix b/gnu/egcs/gcc/config/i386/t-interix new file mode 100644 index 00000000000..4c6d84f1b39 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-interix @@ -0,0 +1,16 @@ +# t-interix +LIBGCC1 = libgcc1-asm.a +CROSS_LIBGCC1 = libgcc1-asm.a + +LIB1ASMSRC = i386/cygwin.asm +LIB1ASMFUNCS = _chkstk + +interix.o: $(srcdir)/config/i386/interix.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/interix.c + +# System headers will track gcc's needs. +# Even LANG_EXTRA_HEADERS may be temporary. +USER_H=$(LANG_EXTRA_HEADERS) + +# We don't want this one either. +INSTALL_ASSERT_H= diff --git a/gnu/egcs/gcc/config/i386/t-mingw32 b/gnu/egcs/gcc/config/i386/t-mingw32 new file mode 100644 index 00000000000..fe948c6d15e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-mingw32 @@ -0,0 +1,4 @@ +# +# collect2 doesn't work for i386-mingw32* yet. +# +USE_COLLECT2= diff --git a/gnu/egcs/gcc/config/i386/t-next b/gnu/egcs/gcc/config/i386/t-next new file mode 100644 index 00000000000..effa6953b9a --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-next @@ -0,0 +1,12 @@ +# libgcc1.c is not needed, since the standard library has these functions. +LIBGCC1=libgcc1.null +CROSS_LIBGCC1=libgcc1.null + +# 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 ] + +nextstep.o: $(srcdir)/config/nextstep.c $(CONFIG_H) flags.h tree.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/nextstep.c diff --git a/gnu/egcs/gcc/config/i386/t-osf b/gnu/egcs/gcc/config/i386/t-osf new file mode 100644 index 00000000000..c996e0c9e77 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-osf @@ -0,0 +1,2 @@ +# If compiling with the osf gcc, avoid sharing code. +TCFLAGS = -pic-none diff --git a/gnu/egcs/gcc/config/i386/t-osf1elf b/gnu/egcs/gcc/config/i386/t-osf1elf new file mode 100644 index 00000000000..77c7df1a6df --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-osf1elf @@ -0,0 +1,18 @@ +# Assemble startup files. +crti.o: $(srcdir)/config/i386/osf1-ci.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/osf1-ci.asm >crti.s + $(GCC_FOR_TARGET) -c -o crti.o crti.s +crtn.o: $(srcdir)/config/i386/osf1-cn.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/osf1-cn.asm >crtn.s + $(GCC_FOR_TARGET) -c -o crtn.o crtn.s + +# The pushl in CTOR initialization interferes with frame pointer elimination. + +# We need to use -fPIC when we are using gcc to compile the routines in +# crtstuff.c. This is only really needed when we are going to use gcc/g++ +# to produce a shared library, but since we don't know ahead of time when +# we will be doing that, we just always use -fPIC when compiling the +# routines in crtstuff.c. + +CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer +TARGET_LIBGCC2_CFLAGS = -fPIC diff --git a/gnu/egcs/gcc/config/i386/t-sco5 b/gnu/egcs/gcc/config/i386/t-sco5 new file mode 100644 index 00000000000..f602066e995 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-sco5 @@ -0,0 +1,20 @@ +# The pushl in CTOR initialization interferes with frame pointer elimination. +CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer +CRTSTUFF_T_CFLAGS_S = -mcoff -fno-omit-frame-pointer + +# +# I am still a little unsure of the multilib architecture. The following +# 4 lines are based on advice from meissner@cygnus.com. +# +MULTILIB_OPTIONS = mcoff/fPIC +MULTILIB_DIRNAMES = coff pic +MULTILIB_EXCEPTIONS = *mcoff*/*fPIC* +MULTILIB_MATCHES = fPIC=fpic +MULTILIB_EXTRA_OPTS = + +LIBGCC=stmp-multilib +INSTALL_LIBGCC=install-multilib + +crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s + $(GCC_FOR_TARGET) -c -o crti.o crti.s diff --git a/gnu/egcs/gcc/config/i386/t-sco5gas b/gnu/egcs/gcc/config/i386/t-sco5gas new file mode 100644 index 00000000000..2bca87be7a8 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-sco5gas @@ -0,0 +1,20 @@ +# The pushl in CTOR initialization interferes with frame pointer elimination. +CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer +CRTSTUFF_T_CFLAGS_S = -mcoff -fno-omit-frame-pointer + +# +# I am still a little unsure of the multilib architecture. The following +# 4 lines are based on advice from meissner@cygnus.com. +# +MULTILIB_OPTIONS = fPIC +MULTILIB_DIRNAMES = pic +MULTILIB_EXCEPTIONS = *fPIC* +MULTILIB_MATCHES = fPIC=fpic +MULTILIB_EXTRA_OPTS = + +LIBGCC=stmp-multilib +INSTALL_LIBGCC=install-multilib + +crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s + $(GCC_FOR_TARGET) -c -o crti.o crti.s diff --git a/gnu/egcs/gcc/config/i386/t-sol2 b/gnu/egcs/gcc/config/i386/t-sol2 new file mode 100644 index 00000000000..5dc59cc375e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-sol2 @@ -0,0 +1,40 @@ +# we need to supply our own assembly versions of libgcc1.c files, +# since the user may not have native 'cc' available + +LIBGCC1 = libgcc1.null +CROSS_LIBGCC1 = libgcc1.null + +# gmon build rule: +gmon.o: $(srcdir)/config/i386/gmon-sol2.c $(GCC_PASSES) $(CONFIG_H) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \ + -c $(srcdir)/config/i386/gmon-sol2.c -o gmon.o + +# Assemble startup files. +# Apparently Sun believes that assembler files don't need comments, because no +# single ASCII character is valid (tried them all). So we manually strip out +# the comments with sed. This bug may only be in the Early Access releases. +gcrt1.o: $(srcdir)/config/i386/sol2-gc1.asm + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-gc1.asm >gcrt1.s + $(AS) -o gcrt1.o gcrt1.s +crt1.o: $(srcdir)/config/i386/sol2-c1.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-c1.asm >crt1.s + $(GCC_FOR_TARGET) -c -o crt1.o crt1.s +crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s + $(GCC_FOR_TARGET) -c -o crti.o crti.s +crtn.o: $(srcdir)/config/i386/sol2-cn.asm $(GCC_PASSES) + sed -e '/^!/d' <$(srcdir)/config/i386/sol2-cn.asm >crtn.s + $(GCC_FOR_TARGET) -c -o crtn.o crtn.s + +# We need to use -fPIC when we are using gcc to compile the routines in +# crtstuff.c. This is only really needed when we are going to use gcc/g++ +# to produce a shared library, but since we don't know ahead of time when +# we will be doing that, we just always use -fPIC when compiling the +# routines in crtstuff.c. +# +# We must also enable optimization to avoid having any code appear after +# the call & alignment statement, but before we switch back to the +# .text section. + +CRTSTUFF_T_CFLAGS = -fPIC -O2 +TARGET_LIBGCC2_CFLAGS = -fPIC diff --git a/gnu/egcs/gcc/config/i386/t-svr3dbx b/gnu/egcs/gcc/config/i386/t-svr3dbx new file mode 100644 index 00000000000..51711379191 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-svr3dbx @@ -0,0 +1,7 @@ +# gas 1.38.1 supporting dbx-in-coff requires a link script. + +svr3.ifile: $(srcdir)/config/i386/svr3.ifile + rm -f svr3.ifile; cp $(srcdir)/config/i386/svr3.ifile . + +svr3z.ifile: $(srcdir)/config/i386/svr3z.ifile + rm -f svr3z.ifile; cp $(srcdir)/config/i386/svr3z.ifile . diff --git a/gnu/egcs/gcc/config/i386/t-udk b/gnu/egcs/gcc/config/i386/t-udk new file mode 100644 index 00000000000..96e18643979 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-udk @@ -0,0 +1,2 @@ +# Tell fixincludes to work on this set of headers +SYSTEM_HEADER_DIR = /udk/usr/include diff --git a/gnu/egcs/gcc/config/i386/t-uwin b/gnu/egcs/gcc/config/i386/t-uwin new file mode 100644 index 00000000000..8e598683cdc --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-uwin @@ -0,0 +1,5 @@ +# +# This is included *after* t-cygwin to override LIB1ASMSRC. +# +LIB1ASMSRC = i386/uwin.asm + diff --git a/gnu/egcs/gcc/config/i386/t-vsta b/gnu/egcs/gcc/config/i386/t-vsta new file mode 100644 index 00000000000..6160b7ec945 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-vsta @@ -0,0 +1,2 @@ +LIBGCC1 = libgcc1.null +CROSS_LIBGCC1 = libgcc1.null diff --git a/gnu/egcs/gcc/config/i386/t-winnt b/gnu/egcs/gcc/config/i386/t-winnt new file mode 100644 index 00000000000..1e3557c1822 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/t-winnt @@ -0,0 +1,6 @@ +winnt.o: $(srcdir)/config/i386/winnt.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/winnt.c +oldnames.o: $(srcdir)/config/winnt/oldnames.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/winnt/oldnames.c +spawnv.o: $(srcdir)/config/winnt/spawnv.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/winnt/spawnv.c diff --git a/gnu/egcs/gcc/config/i386/udk.h b/gnu/egcs/gcc/config/i386/udk.h new file mode 100644 index 00000000000..2714e6da1be --- /dev/null +++ b/gnu/egcs/gcc/config/i386/udk.h @@ -0,0 +1,30 @@ +/* Configuration for i386 interfacing with SCO's Universal Development Kit + probably running on OpenServer 5, Unixware 2, or Unixware 5 + */ + + +/* We're very much the SVR4 target with "/udk" prepended to everything that's + interesting */ + +#include "i386/sysv5.h" + +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/udk/usr/ccs/bin/" + +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/udk/usr/ccs/lib/" + +#define STANDARD_INCLUDE_DIR "/udk/usr/include" + +#undef LINK_SPEC +#define LINK_SPEC "%{h*} %{v:-V} \ + %{b} %{Wl,*:%*} \ + %{static:-dn -Bstatic} \ + %{shared:-G -dy -z text} \ + %{symbolic:-Bsymbolic -G -dy -z text} \ + %{G:-G} \ + %{YP,*} \ + %{!YP,*:%{p:-Y P,/udk/usr/ccs/lib/libp:/udk/usr/lib/libp:/udk/usr/ccs/lib:/udk/usr/lib} \ + %{!p:-Y P,/udk/usr/ccs/lib:/usr/lib}} \ + %{Qy:} %{!Qn:-Qy}" + diff --git a/gnu/egcs/gcc/config/i386/unix.h b/gnu/egcs/gcc/config/i386/unix.h new file mode 100644 index 00000000000..771d802b409 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/unix.h @@ -0,0 +1,190 @@ +/* Definitions for Unix assembler syntax for the Intel 80386. + Copyright (C) 1988, 1994, 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. */ + +/* This file defines the aspects of assembler syntax + that are the same for all the i386 Unix systems + (though they may differ in non-Unix systems). */ + +/* Define some concatenation macros to concatenate an opcode + and one, two or three operands. In other assembler syntaxes + they may alter the order of ther operands. */ + +/* Note that the other files fail to use these + in some of the places where they should. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +#define AS2(a,b,c) #a " " #b "," #c +#define AS2C(b,c) " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS2C(b,c) " b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif + +/* Define macro used to output shift-double opcodes when the shift + count is in %cl. Some assemblers require %cl as an argument; + some don't. This macro controls what to do: by default, don't + print %cl. */ +#define SHIFT_DOUBLE_OMITS_COUNT 1 +#define AS3_SHIFT_DOUBLE(a,b,c,d) \ + (SHIFT_DOUBLE_OMITS_COUNT ? AS2 (a,c,d) : AS3 (a,b,c,d)) + +/* Output the size-letter for an opcode. + CODE is the letter used in an operand spec (L, B, W, S or Q). + CH is the corresponding lower case letter + (except if CODE is `Q' then CH is `l', unless GAS_MNEMONICS). */ +#define PUT_OP_SIZE(CODE,CH,FILE) putc (CH,(FILE)) + +/* Opcode suffix for fullword insn. */ +#define L_SIZE "l" + +/* Prefix for register names in this syntax. */ +#define RP "%" + +/* Prefix for immediate operands in this syntax. */ +#define IP "$" + +/* Indirect call instructions should use `*'. */ +#define USE_STAR 1 + +/* Prefix for a memory-operand X. */ +#define PRINT_PTR(X, FILE) + +/* Delimiters that surround base reg and index reg. */ +#define ADDR_BEG(FILE) putc('(', (FILE)) +#define ADDR_END(FILE) putc(')', (FILE)) + +/* Print an index register (whose rtx is IREG). */ +#define PRINT_IREG(FILE,IREG) \ + do \ + { fputs (",", (FILE)); PRINT_REG ((IREG), 0, (FILE)); } \ + while (0) + +/* Print an index scale factor SCALE. */ +#define PRINT_SCALE(FILE,SCALE) \ + if ((SCALE) != 1) fprintf ((FILE), ",%d", (SCALE)) + +/* Print a base/index combination. + BREG is the base reg rtx, IREG is the index reg rtx, + and SCALE is the index scale factor (an integer). */ + +#define PRINT_B_I_S(BREG,IREG,SCALE,FILE) \ + { ADDR_BEG (FILE); \ + if (BREG) PRINT_REG ((BREG), 0, (FILE)); \ + if ((IREG) != 0) \ + { PRINT_IREG ((FILE), (IREG)); \ + PRINT_SCALE ((FILE), (SCALE)); } \ + ADDR_END (FILE); } + +/* Define the syntax of pseudo-ops, labels and comments. */ + +/* String containing the assembler's comment-starter. */ + +#define ASM_COMMENT_START "/" + +/* 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 (initialized) data. */ + +#define DATA_SECTION_ASM_OP ".data" + +/* Output before writable (uninitialized) data. */ + +#define BSS_SECTION_ASM_OP ".bss" + +/* 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) \ + (fputs (".globl ", FILE), assemble_name (FILE, NAME), fputs ("\n", FILE)) + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387. */ + +#define TARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS) + +/* Floating-point return values come in the FP register. */ + +#define VALUE_REGNO(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + && TARGET_FLOAT_RETURNS_IN_80387 ? FIRST_FLOAT_REG : 0) + +/* 1 if N is a possible register number for a function value. */ + +#define FUNCTION_VALUE_REGNO_P(N) \ + ((N) == 0 || ((N)== FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)) + +/* 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 { \ + tree parm; \ + \ + if (i386_regparm > 0) \ + parm = TYPE_ARG_TYPES (TREE_TYPE (function)); \ + else \ + parm = NULL_TREE; \ + for (; parm; parm = TREE_CHAIN (parm)) \ + if (TREE_VALUE (parm) == void_type_node) \ + break; \ + fprintf (FILE, "\taddl $%d,%s\n", DELTA, \ + parm ? "%eax" \ + : aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? "8(%esp)" \ + : "4(%esp)"); \ + \ + if (flag_pic) \ + { \ + rtx xops[2]; \ + xops[0] = pic_offset_table_rtx; \ + xops[1] = (rtx) gen_label_rtx (); \ + \ + if (i386_regparm > 2) \ + abort (); \ + output_asm_insn ("push%L0 %0", xops); \ + output_asm_insn (AS1 (call,%P1), xops); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", CODE_LABEL_NUMBER (xops[1])); \ + output_asm_insn (AS1 (pop%L0,%0), xops); \ + output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); \ + fprintf (FILE, "\tmovl "); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "@GOT(%%ebx),%%ecx\n\tpopl %%ebx\n\tjmp *%%ecx\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tjmp "); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "\n"); \ + } \ +} while (0) diff --git a/gnu/egcs/gcc/config/i386/uwin.asm b/gnu/egcs/gcc/config/i386/uwin.asm new file mode 100644 index 00000000000..6268343f4c0 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/uwin.asm @@ -0,0 +1,32 @@ +/* stuff needed for libgcc1 on win32. */ + +#ifdef L_chkstk + + .global __chkstk + .global __alloca +__chkstk: +__alloca: + pushl %ecx /* save temp */ + movl %esp,%ecx /* get sp */ + addl $0x8,%ecx /* and point to return addr */ + +probe: cmpl $0x1000,%eax /* > 4k ?*/ + jb done + + subl $0x1000,%ecx /* yes, move pointer down 4k*/ + orl $0x0,(%ecx) /* probe there */ + subl $0x1000,%eax /* decrement count */ + jmp probe /* and do it again */ + +done: subl %eax,%ecx + orl $0x0,(%ecx) /* less that 4k, just peek here */ + + movl %esp,%eax + movl %ecx,%esp /* decrement stack */ + + movl (%eax),%ecx /* recover saved temp */ + movl 4(%eax),%eax /* get return address */ + jmp *%eax + + +#endif diff --git a/gnu/egcs/gcc/config/i386/uwin.h b/gnu/egcs/gcc/config/i386/uwin.h new file mode 100644 index 00000000000..0d5019d5b04 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/uwin.h @@ -0,0 +1,93 @@ +/* Operating system specific defines to be used when targeting GCC for + hosting on U/WIN (Windows32), using GNU tools and the Windows32 API + Library, as distinct from winnt.h, which is used to build GCC for use + with a windows style library and tool set and uses the Microsoft tools. + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Mumit Khan <khan@xraylith.wisc.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. */ + +/* Most of this is the same as for Cygwin32, except for changing some + specs. */ + +#include "i386/cygwin.h" + +#define STANDARD_INCLUDE_COMPONENT "UWIN" +#define SYSTEM_INCLUDE_DIR "/usr/gnu/include" + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__i386__ -D_WIN32 -D__WIN32__ \ + -D_UWIN -DWINNT -D_X86_=1 -D__STDC__=1 \ + -D__UWIN__ -D__MSVCRT__ \ + -D_STD_INCLUDE_DIR=mingw32 \ + -D__stdcall=__attribute__((__stdcall__)) \ + _D_stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -D__declspec(x)=__attribute__((x)) \ + -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + +#undef CPP_SPEC +#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ + -include /usr/include/astwin32.h \ + -iprefix /usr/gnu/include -iwithprefix /mingw32" + +/* For Windows applications, include more libraries, but always include + kernel32. */ +#undef LIB_SPEC +#define LIB_SPEC \ + "%{mwindows:-luser32 -lgdi32 -lcomdlg32} -lkernel32 -ladvapi32" + +/* This is needed in g77spec.c for now. Will be removed in the future. */ +#define WIN32_UWIN_TARGET 1 + +/* Include in the mingw32 libraries with libgcc */ +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "-lgnuwin -lposix -lgcc -last -lmoldname -lmsvcrt" + +/* Specify a different entry point when linking a DLL */ +#undef LINK_SPEC +#define LINK_SPEC \ + "%{mwindows:--subsystem windows} %{mdll:--dll -e _DllMainCRTStartup@12}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s}" + +/* These are PE BFD bug workarounds. Should go away eventually. */ + +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + if (i386_pe_dllexport_name_p (NAME)) \ + { \ + drectve_section (); \ + fprintf ((FILE), "\t.ascii \" -export:%s\"\n", \ + I386_PE_STRIP_ENCODING (NAME)); \ + function_section (DECL); \ + } \ + /* disable i386_pe_declare_function_type for UWIN */ \ + if (0 && write_symbols != SDB_DEBUG) \ + i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) + +#undef ASM_OUTPUT_EXTERNAL +#undef ASM_OUTPUT_EXTERNAL_LIBCALL +#undef ASM_FILE_END + diff --git a/gnu/egcs/gcc/config/i386/v3gas.h b/gnu/egcs/gcc/config/i386/v3gas.h new file mode 100644 index 00000000000..fe558d265b4 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/v3gas.h @@ -0,0 +1,80 @@ +/* Definitions for Intel 386 running system V, using gas. + Copyright (C) 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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include <i386/gas.h> + +/* Add stuff that normally comes from i386v.h */ + +/* longjmp may fail to restore the registers if called from the same + function that called setjmp. To compensate, the compiler avoids + putting variables in registers in functions that use both setjmp + and longjmp. */ + +#define NON_SAVING_SETJMP \ + (current_function_calls_setjmp && current_function_calls_longjmp) + +/* longjmp may fail to restore the stack pointer if the saved frame + pointer is the same as the caller's frame pointer. Requiring a frame + pointer in any function that calls setjmp or longjmp avoids this + problem, unless setjmp and longjmp are called from the same function. + Since a frame pointer will be required in such a function, it is OK + that the stack pointer is not restored. */ + +#undef FRAME_POINTER_REQUIRED +#define FRAME_POINTER_REQUIRED \ + (current_function_calls_setjmp || current_function_calls_longjmp) + +/* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib, adapted to gas */ +#undef ASM_OUTPUT_LOCAL +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ + do { \ + int align = exact_log2 (ROUNDED); \ + if (align > 2) align = 2; \ + if (TARGET_SVR3_SHLIB) \ + { \ + data_section (); \ + ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \ + ASM_OUTPUT_LABEL ((FILE), (NAME)); \ + fprintf ((FILE), "\t.set .,.+%u\n", (ROUNDED)); \ + } \ + else \ + { \ + fputs (".lcomm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%u\n", (ROUNDED)); \ + } \ + } while (0) + +/* Add stuff that normally comes from i386v.h via svr3.h */ + +/* Define the actual types of some ANSI-mandated types. These + definitions should work for most SVR3 systems. */ + +#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 diff --git a/gnu/egcs/gcc/config/i386/vsta.h b/gnu/egcs/gcc/config/i386/vsta.h new file mode 100644 index 00000000000..ee7fab9173f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/vsta.h @@ -0,0 +1,78 @@ +/* Configuration for an i386 running VSTa micro-kernel. + Copyright (C) 1994 Free Software Foundation, Inc. + Contributed by Rob Savoye (rob@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. */ + +#define YES_UNDERSCORES + +#include "i386/gas.h" + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif +#define CPP_PREDEFINES "-Dunix -Di386 -DVSTA \ + -Asystem(unix) -Asystem(vsta) -Acpu(i386) -Amachine(i386)" + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctor, in_dtor + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTOR_SECTION_FUNCTION \ + DTOR_SECTION_FUNCTION + +#define CTOR_SECTION_FUNCTION \ +void \ +ctor_section () \ +{ \ + if (in_section != in_ctor) \ + { \ + fprintf (asm_out_file, "\t.section .ctor\n"); \ + in_section = in_ctor; \ + } \ +} + +#define DTOR_SECTION_FUNCTION \ +void \ +dtor_section () \ +{ \ + if (in_section != in_dtor) \ + { \ + fprintf (asm_out_file, "\t.section .dtor\n"); \ + in_section = in_dtor; \ + } \ +} + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + + diff --git a/gnu/egcs/gcc/config/i386/vxi386.h b/gnu/egcs/gcc/config/i386/vxi386.h new file mode 100644 index 00000000000..0bd27b4a189 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/vxi386.h @@ -0,0 +1,62 @@ +/* Definitions of target machine for GNU compiler. VxWorks i386 version. + Copyright (C) 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. */ + +#undef CPP_CPU_SPEC +#define CPP_CPU_SPEC "\ +-Asystem(unix) -Acpu(i386) -Amachine(i386) \ +%{!ansi:-Di386} -D__i386 -D__i386__ \ +%{march=i386:-DCPU=I80386} \ +%{march=i486:-DCPU=I80486 %(cpp_486)} \ +%{march=pentium:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUM %(cpp_586)} \ +%{march=pentiumpro:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUMPRO %(cpp_686)} \ +%{!march=*: \ + %{mcpu=i386:-DCPU=I80386} \ + %{mcpu=i486:-DCPU=I80486 %(cpp_486)} %{m486:-DCPU=I80486 %(cpp_486)} \ + %{mpentium:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUM %(cpp_586)} \ + %{mcpu=pentium:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUM %(cpp_586)} \ + %{mpentiumpro:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUMPRO %(cpp_686)} \ + %{mcpu=pentiumpro:-DCPU=PENTIUM -DCPU_VARIANT=PENTIUMPRO %(cpp_686)} \ + %{!mcpu*:%{!m486:%{!mpentium*:-DCPU=I80386 %(cpp_cpu_default)}}}}" + +#include "i386/i386-aout.h" + +#define HANDLE_SYSV_PRAGMA + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__vxworks -D__i386__" + +/* VxWorks does all the library stuff itself. */ + +#undef LIB_SPEC +#define LIB_SPEC "" + +/* VxWorks uses object files, not loadable images. make linker just + combine objects. */ + +#undef LINK_SPEC +#define LINK_SPEC "-r" + +/* VxWorks provides the functionality of crt0.o and friends itself. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "" diff --git a/gnu/egcs/gcc/config/i386/win-nt.h b/gnu/egcs/gcc/config/i386/win-nt.h new file mode 100644 index 00000000000..97f10c39d00 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/win-nt.h @@ -0,0 +1,150 @@ +/* Operating system specific defines to be used when targeting GCC for + Windows NT 3.x on an i386. + Copyright (C) 1994, 1995 Free Software Foundation, Inc. + Contributed by Douglas B. Rupp (drupp@cs.washington.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 YES_UNDERSCORES + +#include "i386/gas.h" + +#ifdef CPP_PREDEFINES +#undef CPP_PREDEFINES +#endif +#define CPP_PREDEFINES "-Dunix -Di386 -DWIN32 -D_WIN32 \ + -DWINNT -D_M_IX86=300 -D_X86_=1 -D__STDC__=0 -DALMOST_STDC -D_MSC_VER=800 \ + -D__stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -D_cdecl=__attribute__((__cdecl__)) \ + -Asystem(unix) -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_UNSIGNED 1 +#define WCHAR_TYPE_SIZE 16 +#define WCHAR_TYPE "short unsigned int" +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 +#define HAVE_ATEXIT 1 + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctor, in_dtor + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTOR_SECTION_FUNCTION \ + DTOR_SECTION_FUNCTION + +#define CTOR_SECTION_FUNCTION \ +void \ +ctor_section () \ +{ \ + if (in_section != in_ctor) \ + { \ + fprintf (asm_out_file, "\t.section .ctor\n"); \ + in_section = in_ctor; \ + } \ +} + +#define DTOR_SECTION_FUNCTION \ +void \ +dtor_section () \ +{ \ + if (in_section != in_dtor) \ + { \ + fprintf (asm_out_file, "\t.section .dtor\n"); \ + in_section = in_dtor; \ + } \ +} + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol + so that we may access it directly in the GOT. + + On i386 running Windows NT, modify the assembler name with a suffix + consisting of an atsign (@) followed by string of digits that represents + the number of bytes of arguments passed to the function, if it has the + attribute STDCALL. */ + +#ifdef ENCODE_SECTION_INFO +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + if (lookup_attribute ("stdcall", \ + TYPE_ATTRIBUTES (TREE_TYPE (DECL)))) \ + XEXP (DECL_RTL (DECL), 0) = \ + gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (DECL)); \ + } \ +while (0) +#endif + +/* The global __fltused is necessary to cause the printf/scanf routines + for outputting/inputting floating point numbers to be loaded. Since this + is kind of hard to detect, we just do it all the time. */ + +#ifdef ASM_FILE_START +#undef ASM_FILE_START +#endif +#define ASM_FILE_START(FILE) \ + do { output_file_directive (FILE, main_input_filename); \ + fprintf (FILE, ".global\t__fltused\n"); \ + } while (0) + +/* if the switch "-mwindows" is passed to ld, then specify to the Microsoft + linker the proper switches and libraries to build a graphical program */ + +#undef LIB_SPEC +#define LIB_SPEC "%{mwindows:-subsystem windows -e _WinMainCRTStartup \ + USER32.LIB%s GDI32.LIB%s COMDLG32.LIB%s WINSPOOL.LIB%s} \ + %{!mwindows:-subsystem console -e _mainCRTStartup} \ + %{mcrtmt:LIBCMT.LIB%s KERNEL32.LIB%s ADVAPI32.LIB%s} \ + %{!mcrtmt:LIBC.LIB%s KERNEL32.LIB%s ADVAPI32.LIB%s} \ + %{v}" + +#include "winnt/win-nt.h" + diff --git a/gnu/egcs/gcc/config/i386/win32.h b/gnu/egcs/gcc/config/i386/win32.h new file mode 100644 index 00000000000..d62abbf16d8 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/win32.h @@ -0,0 +1,280 @@ +/* Operating system specific defines to be used when targeting GCC for + hosting on Windows NT 3.x, using a Unix style C library and tools, + as distinct from winnt.h, which is used to build GCC for use with a + windows style library and tool set and uses the Microsoft tools. + Copyright (C) 1995-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. */ + +#define YES_UNDERSCORES + +/* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop). */ +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +#define DBX_DEBUGGING_INFO +#define SDB_DEBUGGING_INFO +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#include "i386/gas.h" +#include "dbxcoff.h" + +/* Augment TARGET_SWITCHES with the cygwin/win32 options. */ +#define MASK_WIN32 0x40000000 /* Use -lming32 interface */ +#define MASK_CYGWIN 0x20000000 /* Use -lcygwin interface */ +#define MASK_WINDOWS 0x10000000 /* Use windows interface */ +#define MASK_DLL 0x08000000 /* Use dll interface */ +#define MASK_NOP_FUN_DLLIMPORT 0x20000 /* Ignore dllimport for functions */ + +#define TARGET_WIN32 (target_flags & MASK_WIN32) +#define TARGET_CYGWIN (target_flags & MASK_CYGWIN) +#define TARGET_WINDOWS (target_flags & MASK_WINDOWS) +#define TARGET_DLL (target_flags & MASK_DLL) +#define TARGET_NOP_FUN_DLLIMPORT (target_flags & MASK_NOP_FUN_DLLIMPORT) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "win32", MASK_WIN32, "Use Mingw32 interface" }, \ + { "cygwin", MASK_CYGWIN, "Use Cygwin interface" }, \ + { "windows", MASK_WINDOWS, "Use bare Windows interface" }, \ + { "dll", MASK_DLL, "Generate code for a DLL" }, \ + { "nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, "Ignore dllimport for functions" }, \ + { "no-nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, "" }, + + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D_WIN32 \ + -DWINNT -D_X86_=1 -D__STDC__=1\ + -D__stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + -Asystem(winnt)" + +#undef STARTFILE_SPEC + +#define STARTFILE_SPEC "%{mdll:dllcrt0%O%s} %{!mdll: %{!mcygwin:mcrt0%O%s} \ + %{mcygwin:crt0%O%s} %{pg:gcrt0%O%s}}" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ + %{!mcygwin:-iwithprefixbefore include/mingw32 -D__MINGW32__} \ + %{mcygwin:-D__CYGWIN32__ -D__CYGWIN__}" + +/* We have to dynamic link to get to the system DLLs. All of libc, libm and + the Unix stuff is in cygwin.dll. The import library is called + 'libcygwin.a'. For Windows applications, include more libraries, but + always include kernel32. We'd like to specific subsystem windows to + ld, but that doesn't work just yet. */ + +#undef LIB_SPEC +#define LIB_SPEC "%{pg:-lgmon} \ + %{!mcygwin:-lmingw32 -lmoldname -lmsvcrt -lcrtdll} \ + %{mcygwin:-lcygwin} %{mwindows:-luser32 -lgdi32 -lcomdlg32} \ + -lkernel32 -ladvapi32 -lshell32" + +#define LINK_SPEC "%{mwindows:--subsystem windows} \ + %{mdll:--dll -e _DllMainCRTStartup@12}" + +#define SIZE_TYPE "unsigned int" +#define PTRDIFF_TYPE "int" +#define WCHAR_UNSIGNED 1 +#define WCHAR_TYPE_SIZE 16 +#define WCHAR_TYPE "short unsigned int" +/* Currently we do not have the atexit() function, + so take that from libgcc2.c */ + +#define NEED_ATEXIT 1 +#define HAVE_ATEXIT 1 + +#undef EXTRA_SECTIONS +#define EXTRA_SECTIONS in_ctor, in_dtor + +#undef EXTRA_SECTION_FUNCTIONS +#define EXTRA_SECTION_FUNCTIONS \ + CTOR_SECTION_FUNCTION \ + DTOR_SECTION_FUNCTION + +#define CTOR_SECTION_FUNCTION \ +void \ +ctor_section () \ +{ \ + if (in_section != in_ctor) \ + { \ + fprintf (asm_out_file, "\t.section .ctor\n"); \ + in_section = in_ctor; \ + } \ +} + +#define DTOR_SECTION_FUNCTION \ +void \ +dtor_section () \ +{ \ + if (in_section != in_dtor) \ + { \ + fprintf (asm_out_file, "\t.section .dtor\n"); \ + in_section = in_dtor; \ + } \ +} + +#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \ + do { \ + ctor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \ + do { \ + dtor_section (); \ + fprintf (FILE, "%s\t", ASM_LONG); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, "\n"); \ + } while (0) + +/* Define this macro if references to a symbol must be treated + differently depending on something about the variable or + function named by the symbol (such as what section it is in). + + On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol + so that we may access it directly in the GOT. + + On i386 running Windows NT, modify the assembler name with a suffix + consisting of an atsign (@) followed by string of digits that represents + the number of bytes of arguments passed to the function, if it has the + attribute STDCALL. */ + +#ifdef ENCODE_SECTION_INFO +#undef ENCODE_SECTION_INFO +#define ENCODE_SECTION_INFO(DECL) \ +do \ + { \ + if (flag_pic) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) \ + = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \ + || ! TREE_PUBLIC (DECL)); \ + } \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + if (lookup_attribute ("stdcall", \ + TYPE_ATTRIBUTES (TREE_TYPE (DECL)))) \ + XEXP (DECL_RTL (DECL), 0) = \ + gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (DECL)); \ + } \ +while (0) +#endif + +/* This macro gets just the user-specified name + out of the string in a SYMBOL_REF. Discard + trailing @[NUM] encoded by ENCODE_SECTION_INFO. + Do we need the stripping of leading '*'? */ +#undef STRIP_NAME_ENCODING +#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ +do { \ + char *_p; \ + char *_name = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*')); \ + for (_p = _name; *_p && *_p != '@'; ++_p) \ + ; \ + if (*_p == '@') \ + { \ + int _len = _p - _name; \ + (VAR) = (char *) alloca (_len + 1); \ + strncpy ((VAR), _name, _len); \ + (VAR)[_len] = '\0'; \ + } \ + else \ + (VAR) = _name; \ +} while (0) + + +/* Emit code to check the stack when allocating more that 4000 + bytes in one go. */ + +#define CHECK_STACK_LIMIT 4000 + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387 and needs stack probes */ +#undef TARGET_DEFAULT + +#define TARGET_DEFAULT \ + (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE) + +/* 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.align %d\n", 1<<(LOG)) + +/* Define this macro if in some cases global symbols from one translation + unit may not be bound to undefined symbols in another translation unit + without user intervention. For instance, under Microsoft Windows + symbols must be explicitly imported from shared libraries (DLLs). */ +#define MULTIPLE_SYMBOL_SPACES + +#define UNIQUE_SECTION_P(DECL) DECL_ONE_ONLY (DECL) +extern void i386_pe_unique_section (); +#define UNIQUE_SECTION(DECL,RELOC) i386_pe_unique_section (DECL, RELOC) + +#define SUPPORTS_ONE_ONLY 1 + +/* A C statement to output something to the assembler file to switch to section + NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or + NULL_TREE. Some target formats do not support arbitrary sections. Do not + define this macro in such cases. */ +#undef ASM_OUTPUT_SECTION_NAME +#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ +do { \ + if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ + fprintf (STREAM, "\t.section %s,\"x\"\n", (NAME)); \ + else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ + fprintf (STREAM, "\t.section %s,\"\"\n", (NAME)); \ + else \ + fprintf (STREAM, "\t.section %s,\"w\"\n", (NAME)); \ + /* Functions may have been compiled at various levels of \ + optimization so we can't use `same_size' here. Instead, \ + have the linker pick one. */ \ + if ((DECL) && DECL_ONE_ONLY (DECL)) \ + fprintf (STREAM, "\t.linkonce %s\n", \ + TREE_CODE (DECL) == FUNCTION_DECL \ + ? "discard" : "same_size"); \ +} while (0) + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START " #" + +/* DWARF2 Unwinding doesn't work with exception handling yet. */ +#define DWARF2_UNWIND_INFO 0 + +/* Don't assume anything about the header files. */ +#define NO_IMPLICIT_EXTERN_C + +#define SUBTARGET_PROLOGUE \ + if (profile_flag \ + && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),\ + "main") == 0) \ + { \ + rtx xops[1]; \ + xops[0] = gen_rtx_MEM (FUNCTION_MODE, \ + gen_rtx (SYMBOL_REF, Pmode, "_monstartup")); \ + if (do_rtl) \ + emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \ + else \ + output_asm_insn (AS1 (call,%P1), xops); \ + } diff --git a/gnu/egcs/gcc/config/i386/winnt.c b/gnu/egcs/gcc/config/i386/winnt.c new file mode 100644 index 00000000000..f1a2d4b83be --- /dev/null +++ b/gnu/egcs/gcc/config/i386/winnt.c @@ -0,0 +1,570 @@ +/* Subroutines for insn-output.c for Windows NT. + Contributed by Douglas Rupp (drupp@cs.washington.edu) + Copyright (C) 1995, 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. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "output.h" +#include "tree.h" +#include "flags.h" + +/* i386/PE specific attribute support. + + i386/PE has two new attributes: + dllexport - for exporting a function/variable that will live in a dll + dllimport - for importing a function/variable from a dll + + Microsoft allows multiple declspecs in one __declspec, separating + them with spaces. We do NOT support this. Instead, use __declspec + multiple times. +*/ + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. */ + +int +i386_pe_valid_decl_attribute_p (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args == NULL_TREE) + { + if (is_attribute_p ("dllexport", attr)) + return 1; + if (is_attribute_p ("dllimport", attr)) + return 1; + } + + return i386_valid_decl_attribute_p (decl, attributes, attr, args); +} + +/* Return nonzero if ATTR is a valid attribute for TYPE. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. */ + +int +i386_pe_valid_type_attribute_p (type, attributes, attr, args) + tree type; + tree attributes; + tree attr; + tree args; +{ + if (args == NULL_TREE + && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) + { + if (is_attribute_p ("dllexport", attr)) + return 1; + if (is_attribute_p ("dllimport", attr)) + return 1; + } + + return i386_valid_type_attribute_p (type, attributes, attr, args); +} + +/* Merge attributes in decls OLD and NEW. + + This handles the following situation: + + __declspec (dllimport) int foo; + int foo; + + The second instance of `foo' nullifies the dllimport. */ + +tree +i386_pe_merge_decl_attributes (old, new) + tree old, new; +{ + tree a; + int delete_dllimport_p; + + old = DECL_MACHINE_ATTRIBUTES (old); + new = DECL_MACHINE_ATTRIBUTES (new); + + /* What we need to do here is remove from `old' dllimport if it doesn't + appear in `new'. dllimport behaves like extern: if a declaration is + marked dllimport and a definition appears later, then the object + is not dllimport'd. */ + + if (lookup_attribute ("dllimport", old) != NULL_TREE + && lookup_attribute ("dllimport", new) == NULL_TREE) + delete_dllimport_p = 1; + else + delete_dllimport_p = 0; + + a = merge_attributes (old, new); + + if (delete_dllimport_p) + { + tree prev,t; + + /* Scan the list for dllimport and delete it. */ + for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t)) + { + if (is_attribute_p ("dllimport", TREE_PURPOSE (t))) + { + if (prev == NULL_TREE) + a = TREE_CHAIN (a); + else + TREE_CHAIN (prev) = TREE_CHAIN (t); + break; + } + } + } + + return a; +} + +/* Return the type that we should use to determine if DECL is + imported or exported. */ + +static tree +associated_type (decl) + tree decl; +{ + tree t = NULL_TREE; + + /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer + to the containing class. So we look at the 'this' arg. */ + if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + { + /* Artificial methods are not affected by the import/export status of + their class unless they are virtual. */ + if (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl)) + t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))); + } + else if (DECL_CONTEXT (decl) + && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') + t = DECL_CONTEXT (decl); + + return t; +} + +/* Return non-zero if DECL is a dllexport'd object. */ + +int +i386_pe_dllexport_p (decl) + tree decl; +{ + tree exp; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + if (exp) + return 1; + + /* Class members get the dllexport status of their class. */ + if (associated_type (decl)) + { + exp = lookup_attribute ("dllexport", + TYPE_ATTRIBUTES (associated_type (decl))); + if (exp) + return 1; + } + + return 0; +} + +/* Return non-zero if DECL is a dllimport'd object. */ + +int +i386_pe_dllimport_p (decl) + tree decl; +{ + tree imp; + + if (TREE_CODE (decl) == FUNCTION_DECL + && TARGET_NOP_FUN_DLLIMPORT) + return 0; + + if (TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) + return 0; + imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + if (imp) + return 1; + + /* Class members get the dllimport status of their class. */ + if (associated_type (decl)) + { + imp = lookup_attribute ("dllimport", + TYPE_ATTRIBUTES (associated_type (decl))); + if (imp) + return 1; + } + + return 0; +} + +/* Return non-zero if SYMBOL is marked as being dllexport'd. */ + +int +i386_pe_dllexport_name_p (symbol) + char *symbol; +{ + return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; +} + +/* Return non-zero if SYMBOL is marked as being dllimport'd. */ + +int +i386_pe_dllimport_name_p (symbol) + char *symbol; +{ + return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; +} + +/* Mark a DECL as being dllexport'd. + Note that we override the previous setting (eg: dllimport). */ + +void +i386_pe_mark_dllexport (decl) + tree decl; +{ + char *oldname, *newname; + rtx rtlname; + tree idp; + + rtlname = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + if (i386_pe_dllimport_name_p (oldname)) + oldname += 9; + else if (i386_pe_dllexport_name_p (oldname)) + return; /* already done */ + + newname = alloca (strlen (oldname) + 4); + sprintf (newname, "@e.%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + idp = get_identifier (newname); + + XEXP (DECL_RTL (decl), 0) = + gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); +} + +/* Mark a DECL as being dllimport'd. */ + +void +i386_pe_mark_dllimport (decl) + tree decl; +{ + char *oldname, *newname; + tree idp; + rtx rtlname, newrtl; + + rtlname = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (rtlname) == SYMBOL_REF) + oldname = XSTR (rtlname, 0); + else if (GET_CODE (rtlname) == MEM + && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) + oldname = XSTR (XEXP (rtlname, 0), 0); + else + abort (); + if (i386_pe_dllexport_name_p (oldname)) + { + error ("`%s' declared as both exported to and imported from a DLL.", + IDENTIFIER_POINTER (DECL_NAME (decl))); + return; + } + else if (i386_pe_dllimport_name_p (oldname)) + { + /* Already done, but force correct linkage since the redeclaration + might have omitted explicit extern. Sigh. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl)) + { + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + return; + } + + /* ??? One can well ask why we're making these checks here, + and that would be a good question. */ + + /* Imported variables can't be initialized. Note that C++ classes + are marked initial, so we need to check. */ + if (TREE_CODE (decl) == VAR_DECL + && !DECL_VIRTUAL_P (decl) + && (DECL_INITIAL (decl) + && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))) + { + error_with_decl (decl, "initialized variable `%s' is marked dllimport"); + return; + } + /* Nor can they be static. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl) + && 0 /*???*/) + { + error_with_decl (decl, "static variable `%s' is marked dllimport"); + return; + } + + /* `extern' needn't be specified with dllimport. + Specify `extern' now and hope for the best. Sigh. */ + if (TREE_CODE (decl) == VAR_DECL + /* ??? Is this test for vtables needed? */ + && !DECL_VIRTUAL_P (decl)) + { + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + + newname = alloca (strlen (oldname) + 11); + sprintf (newname, "@i._imp__%s", oldname); + + /* We pass newname through get_identifier to ensure it has a unique + address. RTL processing can sometimes peek inside the symbol ref + and compare the string's addresses to see if two symbols are + identical. */ + idp = get_identifier (newname); + + newrtl = gen_rtx (MEM, Pmode, + gen_rtx (SYMBOL_REF, Pmode, + IDENTIFIER_POINTER (idp))); + XEXP (DECL_RTL (decl), 0) = newrtl; + + /* Can't treat a pointer to this as a constant address */ + DECL_NON_ADDR_CONST_P (decl) = 1; +} + +/* Return string which is the former assembler name modified with a + suffix consisting of an atsign (@) followed by the number of bytes of + arguments */ + +char * +gen_stdcall_suffix (decl) + tree decl; +{ + int total = 0; + /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead + of DECL_ASSEMBLER_NAME. */ + char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char *newsym; + + if (TYPE_ARG_TYPES (TREE_TYPE (decl))) + if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl)))) + == void_type_node) + { + tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl)); + + while (TREE_VALUE (formal_type) != void_type_node) + { + int parm_size + = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type))); + /* Must round up to include padding. This is done the same + way as in store_one_arg. */ + parm_size = ((parm_size + PARM_BOUNDARY - 1) + / PARM_BOUNDARY * PARM_BOUNDARY); + total += parm_size; + formal_type = TREE_CHAIN (formal_type); + } + } + + newsym = xmalloc (strlen (asmname) + 10); + sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT); + return IDENTIFIER_POINTER (get_identifier (newsym)); +} + +/* Cover function to implement ENCODE_SECTION_INFO. */ + +void +i386_pe_encode_section_info (decl) + tree decl; +{ + /* This bit is copied from i386.h. */ + if (optimize > 0 && TREE_CONSTANT (decl) + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) + { + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + if (lookup_attribute ("stdcall", + TYPE_ATTRIBUTES (TREE_TYPE (decl)))) + XEXP (DECL_RTL (decl), 0) = + gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl)); + + /* Mark the decl so we can tell from the rtl whether the object is + dllexport'd or dllimport'd. */ + + if (i386_pe_dllexport_p (decl)) + i386_pe_mark_dllexport (decl); + else if (i386_pe_dllimport_p (decl)) + i386_pe_mark_dllimport (decl); + /* It might be that DECL has already been marked as dllimport, but a + subsequent definition nullified that. The attribute is gone but + DECL_RTL still has @i._imp__foo. We need to remove that. Ditto + for the DECL_NON_ADDR_CONST_P flag. */ + else if ((TREE_CODE (decl) == FUNCTION_DECL + || TREE_CODE (decl) == VAR_DECL) + && DECL_RTL (decl) != NULL_RTX + && GET_CODE (DECL_RTL (decl)) == MEM + && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM + && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF + && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) + { + char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); + tree idp = get_identifier (oldname + 9); + rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); + + XEXP (DECL_RTL (decl), 0) = newrtl; + + DECL_NON_ADDR_CONST_P (decl) = 0; + + /* We previously set TREE_PUBLIC and DECL_EXTERNAL. + We leave these alone for now. */ + } +} + +/* Cover function for UNIQUE_SECTION. */ + +void +i386_pe_unique_section (decl, reloc) + tree decl; + int reloc; +{ + int len; + char *name,*string,*prefix; + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + /* Strip off any encoding in fnname. */ + STRIP_NAME_ENCODING (name, name); + + /* The object is put in, for example, section .text$foo. + The linker will then ultimately place them in .text + (everything from the $ on is stripped). Don't put + read-only data in .rdata section to avoid a PE linker + bug when .rdata$* grouped sections are used in code + without a .rdata section. */ + if (TREE_CODE (decl) == FUNCTION_DECL) + prefix = ".text$"; + else if (DECL_READONLY_SECTION (decl, reloc)) +#ifdef READONLY_DATA_SECTION + prefix = ".rdata$"; +#else + prefix = ".text$"; +#endif + else + prefix = ".data$"; + len = strlen (name) + strlen (prefix); + string = alloca (len + 1); + sprintf (string, "%s%s", prefix, name); + + DECL_SECTION_NAME (decl) = build_string (len, string); +} + +/* The Microsoft linker requires that every function be marked as + DT_FCN. When using gas on cygwin, we must emit appropriate .type + directives. */ + +#include "gsyms.h" + +/* Mark a function appropriately. This should only be called for + functions for which we are not emitting COFF debugging information. + FILE is the assembler output file, NAME is the name of the + function, and PUBLIC is non-zero if the function is globally + visible. */ + +void +i386_pe_declare_function_type (file, name, public) + FILE *file; + char *name; + int public; +{ + fprintf (file, "\t.def\t"); + assemble_name (file, name); + fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n", + public ? (int) C_EXT : (int) C_STAT, + (int) DT_FCN << N_BTSHFT); +} + +/* Keep a list of external functions. */ + +struct extern_list +{ + struct extern_list *next; + char *name; +}; + +static struct extern_list *extern_head; + +/* Assemble an external function reference. We need to keep a list of + these, so that we can output the function types at the end of the + assembly. We can't output the types now, because we might see a + definition of the function later on and emit debugging information + for it then. */ + +void +i386_pe_record_external_function (name) + char *name; +{ + struct extern_list *p; + + p = (struct extern_list *) permalloc (sizeof *p); + p->next = extern_head; + p->name = name; + extern_head = p; +} + +/* This is called at the end of assembly. For each external function + which has not been defined, we output a declaration now. */ + +void +i386_pe_asm_file_end (file) + FILE *file; +{ + struct extern_list *p; + + for (p = extern_head; p != NULL; p = p->next) + { + tree decl; + + decl = get_identifier (p->name); + + /* Positively ensure only one declaration for any given symbol. */ + if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl)) + { + TREE_ASM_WRITTEN (decl) = 1; + i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl)); + } + } +} diff --git a/gnu/egcs/gcc/config/i386/x-aix b/gnu/egcs/gcc/config/i386/x-aix new file mode 100644 index 00000000000..b191e48fd0f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-aix @@ -0,0 +1,12 @@ +# There is an alloca in -lbsd, but it is limited to 32K +ALLOCA = alloca.o + +# If you are running out of memory while compiling gcc, with the standard +# /bin/cc uncomment MALLOCLIB line. That version of malloc is slower but +# has less overhead than the one in libc. +#MALLOCLIB = -lmalloc + +# Uncomment out the next line if you want to link with the shareable libc_s. +#CLIB_S = -lc_s + +CLIB = -lld $(MALLOCLIB) $(CLIB_S) diff --git a/gnu/egcs/gcc/config/i386/x-cygwin b/gnu/egcs/gcc/config/i386/x-cygwin new file mode 100644 index 00000000000..f251835bd33 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-cygwin @@ -0,0 +1,4 @@ +# Don't run fixproto +STMP_FIXPROTO = +# prefix.c wants to poke around the Registry +CLIB = -ladvapi32 diff --git a/gnu/egcs/gcc/config/i386/x-dgux b/gnu/egcs/gcc/config/i386/x-dgux new file mode 100644 index 00000000000..322bfe3ae91 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-dgux @@ -0,0 +1,11 @@ +# +# host is ix86 running dgux +# +CC = /bin/gcc +X_CFLAGS = -O -mstandard -mlegend +BOOT_CFLAGS = -O2 -g -mstandard -mlegend $(CFLAGS) +CLIB = -lw32 +RANLIB = true +USER_H = $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) +STMP_FIXPROTO = + diff --git a/gnu/egcs/gcc/config/i386/x-djgpp b/gnu/egcs/gcc/config/i386/x-djgpp new file mode 100644 index 00000000000..89f31ff5008 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-djgpp @@ -0,0 +1,24 @@ +# translate the version string, so it can be used on DJGPP, where only +# one dot in filename is allowed + +# to avoid recursion when redefining $(version) +_version:=$(version) +__version=$(subst ., ,$(_version)) +version=$(word 1,$(__version))$(word 2,$(__version)).$(word 3,$(__version)) + +SYSTEM_HEADER_DIR=$(DJDIR)/include +X_CPPFLAGS=-DSTANDARD_INCLUDE_DIR=\"\$$DJDIR/include\" \ + -DSTANDARD_INCLUDE_COMPONENT=\"\" + +# when building a native compiler for DJGPP, make the target_alias +# a shorter name, since otherwise it will produce some problems, when +# using the same gcc once with long filenames and once with short (8+3) +# filenames +ifeq ($(findstring -pc-msdosdjgpp,$(target_alias)),-pc-msdosdjgpp) +target_alias=djgpp +endif + +# on DJGPP the 'ln -s' does not work correctly +LN = cp -p +LN_S = cp -p + diff --git a/gnu/egcs/gcc/config/i386/x-isc b/gnu/egcs/gcc/config/i386/x-isc new file mode 100644 index 00000000000..ea65ec888a3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-isc @@ -0,0 +1,3 @@ +CLIB = -lPW -lcposix +X_CFLAGS = -D_POSIX_SOURCE +ENQUIRE_LDFLAGS = -posix $(LDFLAGS) diff --git a/gnu/egcs/gcc/config/i386/x-isc3 b/gnu/egcs/gcc/config/i386/x-isc3 new file mode 100644 index 00000000000..527cca8132b --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-isc3 @@ -0,0 +1,4 @@ +CLIB = -lPW +# One person said it needs -DPOSIX_JC, but daa@CERF.NET says no. +X_CFLAGS = -D_SYSV3 -Xp +ENQUIRE_LDFLAGS = $(LDFLAGS) diff --git a/gnu/egcs/gcc/config/i386/x-ncr3000 b/gnu/egcs/gcc/config/i386/x-ncr3000 new file mode 100644 index 00000000000..4ae168b1fe5 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-ncr3000 @@ -0,0 +1,34 @@ +# Makefile additions for the NCR3000 as host system. + +# Using -O with the AT&T compiler fails, with a message about a missing +# /usr/ccs/lib/optim pass. So override the default in Makefile.in + +CCLIBFLAGS= + +## Supposedly not needed now that xm-sysv4.h includes alloc.h for Metaware. +### NCR3000 ships with a MetaWare compiler installed as CC, which chokes and +### dies all over the place on GCC source. However, the AT&T compiler, +### crusty as it is, can be used to bootstrap GCC. It can be found in +### /usr/ccs/ATT/cc. It is also used to compile the things that should +### not be compiled with GCC. +## +##CC = /usr/ccs/ATT/cc +##OLDCC = /usr/ccs/ATT/cc + +# The rest is just x-i386v4. + +# Some versions of SVR4 have an alloca in /usr/ucblib/libucb.a, and if we are +# careful to link that in after libc we can use it, but since newer versions of +# SVR4 are dropping libucb, it is better to just use the portable C version for +# bootstrapping. Do this by defining ALLOCA. + +ALLOCA = alloca.o + +# We used to build all stages *without* shared libraries because that may make +# debugging the compiler easier (until there is a GDB which supports +# both Dwarf *and* svr4 shared libraries). + +# But james@bigtex.cactus.org says that redefining GCC_CFLAGS causes trouble, +# and that it is easy enough to debug using shared libraries. +# CCLIBFLAGS=-Bstatic -dn -g +# GCC_CFLAGS=-static -g -O2 -B./ diff --git a/gnu/egcs/gcc/config/i386/x-next b/gnu/egcs/gcc/config/i386/x-next new file mode 100644 index 00000000000..a16b918e2d3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-next @@ -0,0 +1,3 @@ +# Make assignments for compiling on NeXT with their compiler version. +CC=cc -traditional-cpp +OLDCC=cc -traditional-cpp diff --git a/gnu/egcs/gcc/config/i386/x-osf1elf b/gnu/egcs/gcc/config/i386/x-osf1elf new file mode 100644 index 00000000000..146738107f6 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-osf1elf @@ -0,0 +1,8 @@ +# Defaults for OSF/1 1.3+ +CC = $(OLDCC) +CLIB = -lld +INSTALL = installbsd -c +OLDCC = /usr/ccs/gcc/gcc +X_CFLAGS = -static + +# FIXPROTO_DEFINES = -D_XOPEN_SOURCE diff --git a/gnu/egcs/gcc/config/i386/x-osfrose b/gnu/egcs/gcc/config/i386/x-osfrose new file mode 100644 index 00000000000..2c5e3ba13c7 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-osfrose @@ -0,0 +1,27 @@ +# Define CC and OLDCC as the same, so that the tests: +# if [ x"$(OLDCC)" = x"$(CC)" ] ... +# +# will succeed (if OLDCC != CC, it is assumed that GCC is +# being used in secondary stage builds). + +BUILD = +CC = $(OLDCC) +CLIB = -lld +X_CFLAGS = $(DEB_OPT) $(MSTATS) $(X_DEFINES) +X_CFLAGS_NODEBUG = $(NO_DEBUG) $(MSTATS) $(OPT) $(PROFILE) $(X_DEFINES) $(XCFLAGS) +XCFLAGS = $(SHLIB) +CPP_ABORT = # -Dabort=fancy_abort +CPPFLAGS = $(CPP_ABORT) $(SYSTEM_INCLUDES) +DEB_OPT = $(OPT) $(DEBUG) $(PROFILE) +DEBUG = +DEBUG_COLLECT = # -DDEBUG +CCLIBFLAGS = -O -DNO_HALF_PIC +GCC_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) -B./ -DPOSIX -DNO_HALF_PIC +LDFLAGS = +MSTATS = # -mstats +OLDCC = /usr/ccs/gcc/gcc +OPT = -O +PROFILE = +SHLIB = -pic-none +SYSTEM_INCLUDES = # -I${BUILD}/usr/include +X_DEFINES = -Dvfork=fork diff --git a/gnu/egcs/gcc/config/i386/x-sco b/gnu/egcs/gcc/config/i386/x-sco new file mode 100644 index 00000000000..f7f14e9f7c0 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-sco @@ -0,0 +1,7 @@ +RANLIB = : +RANLIB_TEST = false +CC = rcc $(RCCFLAGS) +OLDCC = rcc $(RCCFLAGS) +RCCFLAGS = -Dunix -Di386 -DM_UNIX -DM_I386 -DNULL=0 +CCLIBFLAGS = +CLIB = -lmalloc -lPW diff --git a/gnu/egcs/gcc/config/i386/x-sco4 b/gnu/egcs/gcc/config/i386/x-sco4 new file mode 100644 index 00000000000..be6080f8893 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-sco4 @@ -0,0 +1,10 @@ +RANLIB = : +RANLIB_TEST = false +CC = rcc $(RCCFLAGS) +OLDCC = rcc $(RCCFLAGS) +RCCFLAGS = -Dunix -Di386 -DM_UNIX -DM_I386 -DNULL=0 +CCLIBFLAGS = +CLIB = -lmalloc -lPW + +# See all the declarations. +FIXPROTO_DEFINES = -D_XOPEN_SOURCE diff --git a/gnu/egcs/gcc/config/i386/x-sco5 b/gnu/egcs/gcc/config/i386/x-sco5 new file mode 100644 index 00000000000..e13ed742540 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-sco5 @@ -0,0 +1,10 @@ +RANLIB = : +RANLIB_TEST = false +CC = cc +OLDCC = cc +CCLIBFLAGS = +# We avoid the ALLOCA in -lPW becuase it gives us an evil index() +ALLOCA = alloca.o + +# See all the declarations. +FIXPROTO_DEFINES = -D_XOPEN_SOURCE -D_POSIX_C_SOURCE=2 diff --git a/gnu/egcs/gcc/config/i386/x-sysv3 b/gnu/egcs/gcc/config/i386/x-sysv3 new file mode 100644 index 00000000000..a1391df851c --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-sysv3 @@ -0,0 +1 @@ +CLIB=-lPW diff --git a/gnu/egcs/gcc/config/i386/x-vsta b/gnu/egcs/gcc/config/i386/x-vsta new file mode 100644 index 00000000000..e2279a4b59a --- /dev/null +++ b/gnu/egcs/gcc/config/i386/x-vsta @@ -0,0 +1 @@ +CLIB=-lm diff --git a/gnu/egcs/gcc/config/i386/xm-aix.h b/gnu/egcs/gcc/config/i386/xm-aix.h new file mode 100644 index 00000000000..4cbd36ef518 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-aix.h @@ -0,0 +1,2 @@ +#undef TRUE +#undef FALSE diff --git a/gnu/egcs/gcc/config/i386/xm-bsd386.h b/gnu/egcs/gcc/config/i386/xm-bsd386.h new file mode 100644 index 00000000000..6b8eee7db03 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-bsd386.h @@ -0,0 +1,3 @@ +/* Configuration for GCC for Intel i386 running BSDI's BSD/386 as host. */ + +#include "i386/xm-i386.h" diff --git a/gnu/egcs/gcc/config/i386/xm-cygwin.h b/gnu/egcs/gcc/config/i386/xm-cygwin.h new file mode 100644 index 00000000000..ab59627fce7 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-cygwin.h @@ -0,0 +1,58 @@ +/* Configuration for GNU C-compiler for hosting on Windows NT. + using a unix style C library. + Copyright (C) 1995, 1996, 1997, 1998, 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. */ + +#define EXECUTABLE_SUFFIX ".exe" +#define NO_SYS_SIGLIST 1 + +/* We support both "/" and "\" since everybody tests both but we + default to "/". This is important because if gcc produces Win32 + paths containing backslashes, make and configure may treat the + backslashes as escape characters. Many Win32 programs use forward + slashes so using a forward slash shouldn't be problematic from the + perspective of wanting gcc to produce native Win32 paths. */ +#define DIR_SEPARATOR '/' +#define DIR_SEPARATOR_2 '\\' + +/* Convert win32 style path lists to POSIX style for consistency. */ +#undef GET_ENV_PATH_LIST +#define GET_ENV_PATH_LIST(VAR,NAME) \ +do { \ + char *_epath; \ + char *_posixepath; \ + _epath = _posixepath = getenv (NAME); \ + /* if we have a posix path list, convert to posix path list */ \ + if (_epath != NULL && *_epath != 0 \ + && ! cygwin_posix_path_list_p (_epath)) \ + { \ + char *p; \ + _posixepath = (char *) xmalloc \ + (cygwin_win32_to_posix_path_list_buf_size (_epath)); \ + cygwin_win32_to_posix_path_list (_epath, _posixepath); \ + } \ + (VAR) = _posixepath; \ +} while (0) + +#define PATH_SEPARATOR ':' + +/* This is needed so that protoize will compile. */ +#ifndef POSIX +#define POSIX +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-dgux.h b/gnu/egcs/gcc/config/i386/xm-dgux.h new file mode 100644 index 00000000000..5bdb9be0ebb --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-dgux.h @@ -0,0 +1,12 @@ + +/* Configuration for GCC for Intel i386 running DG/ux */ + +/* looks just like sysv4 for now */ + +#include "i386/xm-i386.h" +#include "xm-svr4.h" + +/* If not compiled with GNU C, use the portable alloca. */ +#ifndef __GNUC__ +#define USE_C_ALLOCA +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-djgpp.h b/gnu/egcs/gcc/config/i386/xm-djgpp.h new file mode 100644 index 00000000000..50034fd071d --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-djgpp.h @@ -0,0 +1,46 @@ +/* Configuration for GNU C-compiler for Intel 80386 running DJGPP. + Copyright (C) 1988, 1996, 1998, 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. */ + +#define __MSDOS__ 1 + +#include "i386/xm-i386.h" + +/* Use semicolons to separate elements of a path. */ +#define PATH_SEPARATOR ';' + +#define EXECUTABLE_SUFFIX ".exe" + +/* Even though we support "/", allow "\" since everybody tests both. */ +#define DIR_SEPARATOR '/' +#define DIR_SEPARATOR_2 '\\' + +/* Allow test for DOS drive names. */ +#define HAVE_DOS_BASED_FILESYSTEM + +#define NO_SYS_SIGLIST 1 + +#define LIBSTDCXX "-lstdcxx" + +/* System dependant initialization for collect2 + to tell system() to act like Unix. */ +#define COLLECT2_HOST_INITIALIZATION \ + do { __system_flags |= (__system_allow_multiple_cmds \ + | __system_emulate_chdir); } while (0) + diff --git a/gnu/egcs/gcc/config/i386/xm-dos.h b/gnu/egcs/gcc/config/i386/xm-dos.h new file mode 100644 index 00000000000..4e1cb42c8c1 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-dos.h @@ -0,0 +1,38 @@ +/* Configuration for GNU C-compiler for Intel 80386 running DOS. + Copyright (C) 1998, 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. */ + +#include "i386/xm-i386.h" + +/* Use semicolons to separate elements of a path. */ +#define PATH_SEPARATOR ';' + +/* Use backslashs to separate levels of directory. */ +#define DIR_SEPARATOR '\\' +#define DIR_SEPARATOR_2 '/' + +/* Allow checks for drive names. */ +#define HAVE_DOS_BASED_FILE_SYSTEM + +/* Suffix for executable file names. */ +#define EXECUTABLE_SUFFIX ".exe" + +#define MKTEMP_EACH_FILE 1 + +#define NO_PRECOMPILES 1 diff --git a/gnu/egcs/gcc/config/i386/xm-freebsd.h b/gnu/egcs/gcc/config/i386/xm-freebsd.h new file mode 100644 index 00000000000..007a609f263 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-freebsd.h @@ -0,0 +1,4 @@ +/* Configuration for GCC for Intel i386 running FreeBSD as host. */ + +#include <i386/xm-i386.h> +#include <xm-freebsd.h> diff --git a/gnu/egcs/gcc/config/i386/xm-gnu.h b/gnu/egcs/gcc/config/i386/xm-gnu.h new file mode 100644 index 00000000000..0b5985f9065 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-gnu.h @@ -0,0 +1,5 @@ +/* Configuration for GCC for Intel i386 running GNU as host. */ + +#include <i386/xm-i386.h> +#include <xm-gnu.h> + diff --git a/gnu/egcs/gcc/config/i386/xm-i386-interix.h b/gnu/egcs/gcc/config/i386/xm-i386-interix.h new file mode 100644 index 00000000000..8bfd5e2d915 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-i386-interix.h @@ -0,0 +1,34 @@ +/* Configuration for GNU compiler + for an Intel i386 or later processor running Interix. + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Donn Terry (donn@interix.com) + Derived from code by Douglas B. Rupp (drupp@cs.washington.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. */ + +#include <i386/xm-i386.h> + +#define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONGLONG +#ifdef __GNUC__ +# define HOST_WIDEST_INT long long +#else +# define HOST_WIDEST_INT __int64 +#endif +#define HOST_WIDEST_INT_PRINT_DEC "%lld" +#define HOST_WIDEST_INT_PRINT_UNSIGNED "%llu" +#define HOST_WIDEST_INT_PRINT_HEX "0x%llx" diff --git a/gnu/egcs/gcc/config/i386/xm-i386.h b/gnu/egcs/gcc/config/i386/xm-i386.h new file mode 100644 index 00000000000..acc16576709 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-i386.h @@ -0,0 +1,43 @@ +/* Configuration for GNU C-compiler for Intel 80386. + Copyright (C) 1988, 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. */ + +#ifndef i386 +#define i386 +#endif + +/* #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 + +/* Arguments to use with `exit'. */ +#define SUCCESS_EXIT_CODE 0 +#define FATAL_EXIT_CODE 33 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gnu/egcs/gcc/config/i386/xm-isc.h b/gnu/egcs/gcc/config/i386/xm-isc.h new file mode 100644 index 00000000000..e686c5ec9d4 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-isc.h @@ -0,0 +1,4 @@ +#ifndef REAL_ARITHMETIC +#define REAL_VALUE_ATOF(x, mode) strtod ((x), (char **)0) +extern double strtod (); +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-linux.h b/gnu/egcs/gcc/config/i386/xm-linux.h new file mode 100644 index 00000000000..713bf3b2817 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-linux.h @@ -0,0 +1,24 @@ +/* Configuration for GCC for Intel i386 running Linux-based GNU systems. + Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc. + Contributed by H.J. Lu (hjl@nynexst.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 <i386/xm-i386.h> +#include <xm-linux.h> + diff --git a/gnu/egcs/gcc/config/i386/xm-lynx.h b/gnu/egcs/gcc/config/i386/xm-lynx.h new file mode 100644 index 00000000000..359e41bbe24 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-lynx.h @@ -0,0 +1,33 @@ +/* Configuration for GNU C-compiler for i386 platforms running LynxOS. + Copyright (C) 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 + +/* target machine dependencies. + tm.h is a symbolic link to the actual target specific file. */ + +#include "tm.h" diff --git a/gnu/egcs/gcc/config/i386/xm-mingw32.h b/gnu/egcs/gcc/config/i386/xm-mingw32.h new file mode 100644 index 00000000000..6872580f33e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-mingw32.h @@ -0,0 +1,48 @@ +/* Configuration for GNU C-compiler for hosting on Windows32. + using GNU tools and the Windows32 API Library. + Copyright (C) 1997, 1998, 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. */ + +#ifndef USG +#define USG 1 +#endif + +#ifndef ONLY_INT_FIELD +#define ONLY_INT_FIELDS 1 +#endif + +#ifndef USE_PROTOTYPES +#define USE_PROTOTYPES 1 +#endif + +#define NO_SYS_SIGLIST 1 +#define environ _environ + +/* Even though we support "/", allow "\" since everybody tests both. */ +#define DIR_SEPARATOR '\\' +#define DIR_SEPARATOR_2 '/' + +/* Mingw32 does not try to hide the underlying DOS-based file system + like Cygwin does. */ +#define HAVE_DOS_BASED_FILE_SYSTEM + +#define EXECUTABLE_SUFFIX ".exe" + +#undef PATH_SEPARATOR +#define PATH_SEPARATOR ';' diff --git a/gnu/egcs/gcc/config/i386/xm-next.h b/gnu/egcs/gcc/config/i386/xm-next.h new file mode 100644 index 00000000000..bf903281a0d --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-next.h @@ -0,0 +1,5 @@ +#include "i386/xm-i386.h" + +/* malloc does better with chunks the size of a page. */ + +#define OBSTACK_CHUNK_SIZE (getpagesize ()) diff --git a/gnu/egcs/gcc/config/i386/xm-openbsd.h b/gnu/egcs/gcc/config/i386/xm-openbsd.h new file mode 100644 index 00000000000..1a79e83bc4a --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-openbsd.h @@ -0,0 +1,23 @@ +/* Configuration file for i386 hosts running OpenBSD. + Copyright (C) 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. */ + +#include <xm-openbsd.h> +#include <i386/xm-i386.h> + diff --git a/gnu/egcs/gcc/config/i386/xm-os2.h b/gnu/egcs/gcc/config/i386/xm-os2.h new file mode 100644 index 00000000000..b8a5ad057a3 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-os2.h @@ -0,0 +1,75 @@ +/* Configuration for GNU compiler + for an Intel i386 or later processor running OS/2 2.x. + Copyright (C) 1993, 1994, 1995, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Samuel Figueroa (figueroa@apple.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. */ + +#ifndef OS2 +#define OS2 +#endif + +#ifdef __IBMC__ +#include <stdlib.h> /* this defines alloca */ +#define USG +#define ONLY_INT_FIELDS +#define USE_PROTOTYPES 1 +#define strcasecmp stricmp +#define kill(a,b) raise(b) +#define mktemp tmpnam +#else +#ifdef __EMX__ +#define EMX +#define USG +#define BSTRING +#define HAVE_PUTENV +#define HAVE_VPRINTF +#define HAVE_STRERROR +#define strcasecmp stricmp +#else +#define ____386BSD____ +int spawnv (int modeflag, char *path, char *argv[]); +int spawnvp (int modeflag, char *path, char *argv[]); +#endif /* __EMX__ */ +#endif /* __IBMC__ */ + +#ifndef PATH_SEPARATOR +#define PATH_SEPARATOR ';' +#endif +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '\\' +#endif +#ifndef DIR_SEPARATOR_2 +#define DIR_SEPARATOR_2 '/' +#endif + +/* Allow handling of drive names. */ +#define HAVE_DOS_BASED_FILE_SYSTEM + +#define EXECUTABLE_SUFFIX ".exe" + +/* The EMX compiler uses regular .o files */ +#ifndef __EMX__ +#define OBJECT_SUFFIX ".obj" +#endif + +/* This is required to make temporary file names unique on file + systems which severely restrict the length of file names. */ +#define MKTEMP_EACH_FILE + +#include "i386/xm-i386.h" diff --git a/gnu/egcs/gcc/config/i386/xm-osf.h b/gnu/egcs/gcc/config/i386/xm-osf.h new file mode 100644 index 00000000000..4cbd36ef518 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-osf.h @@ -0,0 +1,2 @@ +#undef TRUE +#undef FALSE diff --git a/gnu/egcs/gcc/config/i386/xm-osf1elf.h b/gnu/egcs/gcc/config/i386/xm-osf1elf.h new file mode 100644 index 00000000000..69ca9c14c00 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-osf1elf.h @@ -0,0 +1,6 @@ +/* Configuration for GCC for Intel i386 running OSF/1 1.3. */ + +#ifndef HZ +#include <machine/machtime.h> +#define HZ DEFAULT_CLK_TCK +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-sco.h b/gnu/egcs/gcc/config/i386/xm-sco.h new file mode 100644 index 00000000000..ad634499d30 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-sco.h @@ -0,0 +1,13 @@ +/* Configuration for GCC for Intel i386 running SCO. */ + +/* Big buffers improve performance. */ + +#define IO_BUFFER_SIZE (0x8000 - 1024) + +#ifndef __GNUC__ +/* The SCO compiler gets it wrong, and treats enumerated bitfields + as signed quantities, making it impossible to use an 8-bit enum + for compiling GNU C++. */ +#define ONLY_INT_FIELDS 1 +#define CODE_FIELD_BUG 1 +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-sco5.h b/gnu/egcs/gcc/config/i386/xm-sco5.h new file mode 100644 index 00000000000..6b22b1d549f --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-sco5.h @@ -0,0 +1,7 @@ +/* Configuration for GCC for Intel i386 running SCO. */ + +/* Big buffers improve performance. */ + +#define IO_BUFFER_SIZE (0x8000 - 1024) + + diff --git a/gnu/egcs/gcc/config/i386/xm-sun.h b/gnu/egcs/gcc/config/i386/xm-sun.h new file mode 100644 index 00000000000..de7c2013b3e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-sun.h @@ -0,0 +1,23 @@ +/* Configuration for GNU C-compiler for Intel 80386 running SunOS 4.0. + Copyright (C) 1988, 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 + +#include "i386/xm-i386.h" diff --git a/gnu/egcs/gcc/config/i386/xm-sysv3.h b/gnu/egcs/gcc/config/i386/xm-sysv3.h new file mode 100644 index 00000000000..72078bb1feb --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-sysv3.h @@ -0,0 +1,4 @@ +/* Configuration for GCC for Intel i386 running System V Release 3. */ + +#include "i386/xm-i386.h" +#include "xm-svr3.h" diff --git a/gnu/egcs/gcc/config/i386/xm-sysv4.h b/gnu/egcs/gcc/config/i386/xm-sysv4.h new file mode 100644 index 00000000000..1365064a5a6 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-sysv4.h @@ -0,0 +1,5 @@ +/* Configuration for GCC for Intel i386 running System V Release 4. */ + +#ifdef __HIGHC__ +#include <alloca.h> /* for MetaWare High-C on NCR System 3000 */ +#endif diff --git a/gnu/egcs/gcc/config/i386/xm-uwin.h b/gnu/egcs/gcc/config/i386/xm-uwin.h new file mode 100644 index 00000000000..2e1ecde0fa7 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-uwin.h @@ -0,0 +1,39 @@ +/* Configuration for GNU C-compiler for hosting on Windows32. + using GNU tools and the Windows32 API Library. + Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Mumit Khan <khan@xraylith.wisc.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. */ + +#ifndef ONLY_INT_FIELD +#define ONLY_INT_FIELDS 1 +#endif + +#ifndef USE_PROTOTYPES +#define USE_PROTOTYPES 1 +#endif + +/* U/WIN system calls only support '/' */ +#undef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#undef EXECUTABLE_SUFFIX +#define EXECUTABLE_SUFFIX ".exe" + +#undef PATH_SEPARATOR +#define PATH_SEPARATOR ':' + diff --git a/gnu/egcs/gcc/config/i386/xm-vsta.h b/gnu/egcs/gcc/config/i386/xm-vsta.h new file mode 100644 index 00000000000..735d1d51943 --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-vsta.h @@ -0,0 +1,2 @@ +/* Use semicolons to separate elements of a path. */ +#define PATH_SEPARATOR ';' diff --git a/gnu/egcs/gcc/config/i386/xm-winnt.h b/gnu/egcs/gcc/config/i386/xm-winnt.h new file mode 100644 index 00000000000..d36d2cdb11e --- /dev/null +++ b/gnu/egcs/gcc/config/i386/xm-winnt.h @@ -0,0 +1,24 @@ +/* Configuration for GNU compiler + for an Intel i386 or later processor running Windows NT 3.x. + Copyright (C) 1994 Free Software Foundation, Inc. + Contributed by Douglas B. Rupp (drupp@cs.washington.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. */ + +#include "winnt/xm-winnt.h" +#include "i386/xm-i386.h" |