diff options
author | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
commit | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch) | |
tree | 086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/config/i386 | |
parent | 2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff) | |
download | FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz |
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/config/i386')
102 files changed, 34390 insertions, 14463 deletions
diff --git a/contrib/gcc/config/i386/386bsd.h b/contrib/gcc/config/i386/386bsd.h index 7962321..a34e6e5 100644 --- a/contrib/gcc/config/i386/386bsd.h +++ b/contrib/gcc/config/i386/386bsd.h @@ -5,11 +5,8 @@ #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)" +#define CPP_PREDEFINES "-Dunix -D____386BSD____ -D__386BSD__ -DBSD_NET2 -Asystem=unix -Asystem=bsd" /* Like the default, except no -lg. */ #define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}" @@ -28,10 +25,6 @@ #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) \ @@ -54,22 +47,6 @@ #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. */ diff --git a/contrib/gcc/config/i386/aix386.h b/contrib/gcc/config/i386/aix386.h index e0498e7..f085c42 100644 --- a/contrib/gcc/config/i386/aix386.h +++ b/contrib/gcc/config/i386/aix386.h @@ -1,6 +1,6 @@ /* Definitions for IBM PS2 running AIX/386 with gas. From: Minh Tran-Le <TRANLE@intellicorp.com> - Copyright (C) 1988 Free Software Foundation, Inc. + Copyright (C) 1988, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -53,17 +53,12 @@ Boston, MA 02111-1307, USA. */ constructors. */ #undef INIT_SECTION_ASM_OP -#define INIT_SECTION_ASM_OP ".section .init,\"x\"" +#define INIT_SECTION_ASM_OP "\t.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) +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR ix86_svr3_asm_out_constructor diff --git a/contrib/gcc/config/i386/aix386ng.h b/contrib/gcc/config/i386/aix386ng.h index 9a8dae6..445d333 100644 --- a/contrib/gcc/config/i386/aix386ng.h +++ b/contrib/gcc/config/i386/aix386ng.h @@ -44,7 +44,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ -#define CPP_PREDEFINES "-Dps2 -Dunix -Asystem(aix)" +#define CPP_PREDEFINES "-Dps2 -Dunix -Asystem=aix" #define CPP_SPEC "%(cpp_cpu) \ %{posix:-D_POSIX_SOURCE}%{!posix:-DAIX} -D_I386 -D_AIX -D_MBCS" @@ -106,8 +106,8 @@ Boston, MA 02111-1307, USA. */ # undef FINI_SECTION_ASM_OP # undef CTORS_SECTION_ASM_OP # undef DTORS_SECTION_ASM_OP -# undef ASM_OUTPUT_CONSTRUCTOR -# undef ASM_OUTPUT_DESTRUCTOR +# undef TARGET_ASM_CONSTRUCTOR +# undef TARGET_ASM_DESTRUCTOR # undef DO_GLOBAL_CTORS_BODY # undef CTOR_LIST_BEGIN @@ -124,7 +124,6 @@ Boston, MA 02111-1307, USA. */ void \ const_section () \ { \ - extern void text_section(); \ text_section(); \ } diff --git a/contrib/gcc/config/i386/att.h b/contrib/gcc/config/i386/att.h index e5c2d9c..f16a5ea 100644 --- a/contrib/gcc/config/i386/att.h +++ b/contrib/gcc/config/i386/att.h @@ -1,5 +1,5 @@ /* Definitions for AT&T assembler syntax for the Intel 80386. - Copyright (C) 1988, 1996 Free Software Foundation, Inc. + Copyright (C) 1988, 1996, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -30,24 +30,33 @@ Boston, MA 02111-1307, USA. */ /* 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" +#define ASM_SHORT "\t.value\t" +#define ASM_LONG "\t.long\t" +#define ASM_QUAD "\t.quad\t" /* Should not be used for 32bit compilation. */ /* How to output an ASCII string constant. */ -#define ASM_OUTPUT_ASCII(FILE, p, size) \ +#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \ do \ -{ int i = 0; \ - while (i < (size)) \ +{ size_t i = 0, limit = (SIZE); \ + while (i < limit) \ { if (i%10 == 0) { if (i!=0) fprintf ((FILE), "\n"); \ - fprintf ((FILE), "%s ", ASM_BYTE_OP); } \ + fputs ("\t.byte\t", (FILE)); } \ else fprintf ((FILE), ","); \ - fprintf ((FILE), "0x%x", ((p)[i++] & 0377)) ;} \ + fprintf ((FILE), "0x%x", ((PTR)[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 { \ + output_file_directive (FILE, main_input_filename); \ + if (ix86_asm_dialect == ASM_INTEL) \ + fputs ("\t.intel_syntax\n", FILE); \ + } 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") @@ -71,6 +80,10 @@ do \ /* Define the syntax of labels and symbol definitions/declarations. */ +/* The prefix to add for compiler private assembler symbols. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "." + /* 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. @@ -78,16 +91,16 @@ do \ #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "%s%s%ld", LOCAL_LABEL_PREFIX, (PREFIX), (long)(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) + fprintf (FILE, "%s%s%d:\n", LOCAL_LABEL_PREFIX, PREFIX, NUM) -/* The prefix to add to user-visible assembler symbols. */ +/* The prefix to add to user-visible assembler symbols. */ #undef USER_LABEL_PREFIX #define USER_LABEL_PREFIX "" diff --git a/contrib/gcc/config/i386/beos-elf.h b/contrib/gcc/config/i386/beos-elf.h new file mode 100644 index 0000000..be51b4a --- /dev/null +++ b/contrib/gcc/config/i386/beos-elf.h @@ -0,0 +1,250 @@ +/* Definitions for Intel x86 running BeOS + Copyright (C) 1998, 1999, 2000, 2001 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 TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 BeOS/ELF)"); + +/* Change debugging to Dwarf2. */ +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* 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 " #" + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) + +/* 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 "long unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 1 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ELF__ -D__BEOS__ -D__INTEL__ -D_X86_=1 \ +-D__stdcall=__attribute__((__stdcall__)) \ +-D__cdecl=__attribute__((__cdecl__)) \ +-D__declspec(x)=__attribute__((x)) \ +-Asystem=beos" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{!no-fPIC:%{!no-fpic:-D__PIC__ -D__pic__}}" + +/* BeOS uses lots of multichars, so don't warn about them unless the + user explicitly asks for the warnings with -Wmultichar. Note that + CC1_SPEC is used for both cc1 and cc1plus. */ + +#undef CC1_SPEC +#define CC1_SPEC "%{!no-fpic:%{!fPIC:-fpic}} %{!Wmultichar: -Wno-multichar} %(cc1_cpu) %{profile:-p}" + +#undef CC1PLUS_SPEC +#define CC1PLUS_SPEC "%{!Wctor-dtor-privacy:-Wno-ctor-dtor-privacy}" + +/* Provide a LINK_SPEC appropriate for BeOS. 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. */ + +/* If ELF is the default format, we should not use /lib/elf. */ + +#undef LINK_SPEC +#define LINK_SPEC "%{!o*:-o %b} -m elf_i386_be -shared -Bsymbolic %{nostart:-e 0}" + +/* Provide start and end file specs appropriate to glibc. */ + +/* LIB_SPEC for BeOS */ +#undef LIB_SPEC +#define LIB_SPEC "-lnet -lroot" + +/* gcc runtime lib is built into libroot.so on BeOS */ +/* ??? This is gonna be lovely when the next release of gcc has + some new symbol in, so that links start failing. */ +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crti.o%s crtbegin.o%s %{!nostart:start_dyn.o%s} init_term_dyn.o%s %{p:i386-mcount.o%s}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +/* 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) \ + 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 + +/* For native compiler, use standard BeOS include file search paths + rooted in /boot/develop/headers. For a cross compiler, don't + expect the host to use the BeOS directory scheme, and instead look + for the BeOS include files relative to TOOL_INCLUDE_DIR. Yes, we + use ANSI string concatenation here (FIXME) */ + +#ifndef CROSS_COMPILE +#undef INCLUDE_DEFAULTS +#define INCLUDE_DEFAULTS \ + { \ + { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },\ + { GCC_INCLUDE_DIR, "GCC", 0, 0 },\ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1}, \ + { "/boot/develop/headers/be/add-ons/graphics", 0, 0, 0 },\ + { "/boot/develop/headers/be/devel", 0, 0, 0 },\ + { "/boot/develop/headers/be/translation", 0, 0, 0 },\ + { "/boot/develop/headers/be/mail", 0, 0, 0 },\ + { "/boot/develop/headers/gnu", 0, 0, 0 },\ + { "/boot/develop/headers/be/drivers", 0, 0, 0 },\ + { "/boot/develop/headers/be/opengl", 0, 0, 0 },\ + { "/boot/develop/headers/be/game", 0, 0, 0 },\ + { "/boot/develop/headers/be/support", 0, 0, 0 },\ + { "/boot/develop/headers/be/storage", 0, 0, 0 },\ + { "/boot/develop/headers/be/kernel", 0, 0, 0 },\ + { "/boot/develop/headers/be/net", 0, 0, 0 },\ + { "/boot/develop/headers/be/midi", 0, 0, 0 },\ + { "/boot/develop/headers/be/midi2", 0, 0, 0 },\ + { "/boot/develop/headers/be/media", 0, 0, 0 },\ + { "/boot/develop/headers/be/interface", 0, 0, 0 },\ + { "/boot/develop/headers/be/device", 0, 0, 0 },\ + { "/boot/develop/headers/be/app", 0, 0, 0 },\ + { "/boot/develop/headers/be/precompiled", 0, 0, 0 },\ + { "/boot/develop/headers/be/add-ons/input_server", 0, 0, 0 },\ + { "/boot/develop/headers/be/add-ons/net_server", 0, 0, 0 },\ + { "/boot/develop/headers/be/add-ons/screen_saver", 0, 0, 0 },\ + { "/boot/develop/headers/be/add-ons/tracker", 0, 0, 0 },\ + { "/boot/develop/headers/be/be_apps/Deskbar", 0, 0, 0 },\ + { "/boot/develop/headers/be/be_apps/NetPositive", 0, 0, 0 },\ + { "/boot/develop/headers/be/be_apps/Tracker", 0, 0, 0 },\ + { "/boot/develop/headers/be/drivers/tty", 0, 0, 0 },\ + { "/boot/develop/headers/be/net/netinet", 0, 0, 0 },\ + { "/boot/develop/headers/be/storage", 0, 0, 0 },\ + { "/boot/develop/headers/be", 0, 0, 0 },\ + { "/boot/develop/headers/cpp", 0, 0, 0 },\ + { "/boot/develop/headers/posix", 0, 0, 0 },\ + { "/boot/develop/headers", 0, 0, 0 }, \ + { 0, 0, 0, 0 } \ + } +#else /* CROSS_COMPILE */ +#undef INCLUDE_DEFAULTS +#define INCLUDE_DEFAULTS \ + { \ + { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },\ + { GCC_INCLUDE_DIR, "GCC", 0, 0 },\ + { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1}, \ + { CROSS_INCLUDE_DIR "/be/add-ons/graphics", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/devel", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/translation", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/mail", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/gnu", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/drivers", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/opengl", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/game", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/support", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/storage", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/kernel", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/net", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/midi", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/midi2", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/media", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/interface", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/device", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/app", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/precompiled", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/add-ons/input_server", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/add-ons/net_server", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/add-ons/screen_saver", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/add-ons/tracker", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/be_apps/Deskbar", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/be_apps/NetPositive", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/be_apps/Tracker", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/drivers/tty", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/net/netinet", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be/storage", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/be", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/cpp", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR "/posix", 0, 0, 0 },\ + { CROSS_INCLUDE_DIR , 0, 0, 0 }, \ + { 0, 0, 0, 0 } \ + } +#endif + +/* Whee. LIBRARY_PATH is Be's LD_LIBRARY_PATH, which of course will + cause nasty problems if we override it. */ +#define LIBRARY_PATH_ENV "BELIBRARIES" + +/* BeOS doesn't have a separate math library. */ +#define MATH_LIBRARY "" + +/* BeOS headers are C++-aware (and often use C++). */ +#define NO_IMPLICIT_EXTERN_C + +/* 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 diff --git a/contrib/gcc/config/i386/biarch64.h b/contrib/gcc/config/i386/biarch64.h new file mode 100644 index 0000000..e2a5d91 --- /dev/null +++ b/contrib/gcc/config/i386/biarch64.h @@ -0,0 +1,25 @@ +/* Make configure files to produce biarch compiler defaulting to 64bit mode. + This file must be included very first, while the OS specific file later + to overwrite otherwise wrong defaults. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Bo Thorsen <bo@suse.de>. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define TARGET_64BIT_DEFAULT +#define TARGET_BI_ARCH diff --git a/contrib/gcc/config/i386/bsd.h b/contrib/gcc/config/i386/bsd.h index 34db79a..c58db1b 100644 --- a/contrib/gcc/config/i386/bsd.h +++ b/contrib/gcc/config/i386/bsd.h @@ -1,7 +1,7 @@ /* 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. + Copyright (C) 1988, 1996, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -40,10 +40,9 @@ Boston, MA 02111-1307, USA. */ /* 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" +#define ASM_SHORT "\t.word\t" +#define ASM_LONG "\t.long\t" +#define ASM_QUAD "\t.quad\t" /* Should not be used for 32bit compilation. */ /* Output at beginning of assembler file. ??? I am skeptical of this -- RMS. */ @@ -96,10 +95,10 @@ Boston, MA 02111-1307, USA. */ #ifdef NO_UNDERSCORES #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*.%s%ld", (PREFIX), (long)(NUMBER)) #else #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*%s%ld", (PREFIX), (long)(NUMBER)) #endif /* This is how to output an internal numbered label where @@ -113,7 +112,7 @@ Boston, MA 02111-1307, USA. */ fprintf (FILE, "%s%d:\n", PREFIX, NUM) #endif -/* The prefix to add to user-visible assembler symbols. */ +/* The prefix to add to user-visible assembler symbols. */ #ifdef NO_UNDERSCORES #define USER_LABEL_PREFIX "" diff --git a/contrib/gcc/config/i386/bsd386.h b/contrib/gcc/config/i386/bsd386.h index c0dcf87..fb24327 100644 --- a/contrib/gcc/config/i386/bsd386.h +++ b/contrib/gcc/config/i386/bsd386.h @@ -1,12 +1,11 @@ /* 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. */ +/* 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)" +#define CPP_PREDEFINES "-Dunix -Dbsdi -D____386BSD____ -D__386BSD__\ + -DBSD_NET2 -Asystem=unix -Asystem=bsd" #undef WCHAR_TYPE #define WCHAR_TYPE "int" diff --git a/contrib/gcc/config/i386/crtdll.h b/contrib/gcc/config/i386/crtdll.h index 3202af8..f3eae84 100644 --- a/contrib/gcc/config/i386/crtdll.h +++ b/contrib/gcc/config/i386/crtdll.h @@ -1,9 +1,7 @@ /* 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. + hosting on Windows32, using GNU tools and the Windows32 API Library. This variant uses CRTDLL.DLL insted of MSVCRTDLL.DLL. - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -20,21 +18,18 @@ 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. */ +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)" +#define CPP_PREDEFINES "-D_WIN32 -DWIN32 \ + -D__MINGW32__=0.2 -DWINNT -D_X86_=1 \ + -Asystem=winnt" #undef LIBGCC_SPEC -#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lcrtdll" +#define LIBGCC_SPEC \ + "%{mthreads:-lmingwthrd} -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}" +#define STARTFILE_SPEC "%{mdll:dllcrt1%O%s} %{!mdll:crt1%O%s} %{pg:gcrt1%O%s}" diff --git a/contrib/gcc/config/i386/cygwin.asm b/contrib/gcc/config/i386/cygwin.asm index 4ac4c91..a27af31 100644 --- a/contrib/gcc/config/i386/cygwin.asm +++ b/contrib/gcc/config/i386/cygwin.asm @@ -1,4 +1,4 @@ -/* stuff needed for libgcc1 on win32. */ +/* stuff needed for libgcc on win32. */ #ifdef L_chkstk diff --git a/contrib/gcc/config/i386/cygwin.h b/contrib/gcc/config/i386/cygwin.h index dbea466..2a812a5 100644 --- a/contrib/gcc/config/i386/cygwin.h +++ b/contrib/gcc/config/i386/cygwin.h @@ -1,8 +1,7 @@ /* 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. + hosting on Windows32, using a Unix style C library and tools. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. This file is part of GNU CC. @@ -19,7 +18,7 @@ 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. */ +Boston, MA 02111-1307, USA. */ #define YES_UNDERSCORES @@ -27,10 +26,13 @@ Boston, MA 02111-1307, USA. */ #define SDB_DEBUGGING_INFO #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG +#define TARGET_EXECUTABLE_SUFFIX ".exe" + +#include <stdio.h> #include "i386/gas.h" #include "dbxcoff.h" -/* Augment TARGET_SWITCHES with the cygwin/no-cygwin options. */ +/* 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 */ @@ -45,14 +47,53 @@ Boston, MA 02111-1307, USA. */ #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, "" }, +{ "cygwin", MASK_CYGWIN, \ + N_("Use the Cygwin interface") }, \ +{ "no-cygwin", MASK_WIN32, \ + N_("Use the Mingw32 interface") }, \ +{ "windows", MASK_WINDOWS, N_("Create GUI application") }, \ +{ "no-win32", -MASK_WIN32, N_("Don't set Windows defines") },\ +{ "win32", 0, N_("Set Windows defines") }, \ +{ "console", -MASK_WINDOWS, \ + N_("Create console application") }, \ +{ "dll", MASK_DLL, N_("Generate code for a DLL") }, \ +{ "nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, \ + N_("Ignore dllimport for functions") }, \ +{ "no-nop-fun-dllimport", -MASK_NOP_FUN_DLLIMPORT, "" }, \ +{ "threads", 0, N_("Use Mingw-specific thread support") }, +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D_X86_=1 -Asystem=winnt" + +#ifdef CROSS_COMPILE +#define CYGWIN_INCLUDES "%{!nostdinc:-idirafter " CYGWIN_CROSS_DIR "/include}" +#define W32API_INC "%{!nostdinc:-idirafter " CYGWIN_CROSS_DIR "/include/w32api}" +#define W32API_LIB "-L" CYGWIN_CROSS_DIR "/lib/w32api/" +#define CYGWIN_LIB CYGWIN_CROSS_DIR "/lib" +#define MINGW_LIBS "-L" CYGWIN_CROSS_DIR "/lib/mingw" +#define MINGW_INCLUDES "%{!nostdinc:-isystem " CYGWIN_CROSS_DIR "/include/mingw/g++-3 "\ + "-isystem " CYGWIN_CROSS_DIR "/include/mingw/g++ "\ + "-idirafter " CYGWIN_CROSS_DIR "/include/mingw}" +#else +#define CYGWIN_INCLUDES "%{!nostdinc:-isystem /usr/local/include "\ + "-idirafter " CYGWIN_CROSS_DIR "/include "\ + "-idirafter /usr/include}" +#define W32API_INC "%{!nostdinc:"\ + "-idirafter " CYGWIN_CROSS_DIR "/include/w32api "\ + "-idirafter /usr/include/w32api}" +#define W32API_LIB "-L" CYGWIN_CROSS_DIR "/lib/w32api/ -L/usr/lib/w32api/" +#define CYGWIN_LIB "/usr/lib" +#define MINGW_LIBS "-L/usr/local/lib/mingw -L/usr/lib/mingw" +#define MINGW_INCLUDES "%{!nostdinc:-isystem /usr/include/mingw/g++-3 "\ + "-isystem /usr/include/mingw/g++ "\ + "-isystem /usr/local/include/mingw "\ + "-idirafter " CYGWIN_CROSS_DIR "/include/mingw "\ + "-idirafter /usr/include/mingw}" +#endif + +/* Get tree.c to declare a target-specific specialization of + merge_decl_attributes. */ +#define TARGET_DLLIMPORT_DECL_ATTRIBUTES /* Support the __declspec keyword by turning them into attributes. We currently only support: dllimport and dllexport. @@ -62,32 +103,37 @@ Boston, MA 02111-1307, USA. */ 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\ +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ -D__stdcall=__attribute__((__stdcall__)) \ -D__cdecl=__attribute__((__cdecl__)) \ + %{!ansi:-D_stdcall=__attribute__((__stdcall__)) \ + -D_cdecl=__attribute__((__cdecl__))} \ -D__declspec(x)=__attribute__((x)) \ - -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + -D__i386__ -D__i386 \ + %{mno-win32:%{mno-cygwin: %emno-cygwin and mno-win32 are not compatible}} \ + %{mno-cygwin:-D__MSVCRT__ -D__MINGW32__ %{mthreads:-D_MT} "\ + MINGW_INCLUDES "} \ + %{!mno-cygwin:-D__CYGWIN32__ -D__CYGWIN__ %{!ansi:-Dunix} -D__unix__ -D__unix "\ + CYGWIN_INCLUDES "}\ + %{mwin32|mno-cygwin:-DWIN32 -D_WIN32 -D__WIN32 -D__WIN32__ %{!ansi:-DWINNT}}\ + %{!mno-win32:" W32API_INC "}\ +" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "\ + %{shared|mdll: %{mno-cygwin:" MINGW_LIBS " dllcrt2%O%s}}\ + %{!shared: %{!mdll: %{!mno-cygwin:crt0%O%s} %{mno-cygwin:" MINGW_LIBS " crt2%O%s}\ + %{pg:gcrt0%O%s}}}\ +" /* 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}}" + by calling the init function from the prologue. */ -#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}" +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "%{mno-cygwin: %{mthreads:-lmingwthrd} -lmingw32} -lgcc %{mno-cygwin:-lmoldname -lmsvcrt}" /* This macro defines names of additional specifications to put in the specs that can be used in various specifications like CC1_SPEC. Its definition @@ -110,16 +156,26 @@ Boston, MA 02111-1307, USA. */ 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 LIB_SPEC "\ + %{pg:-lgmon} \ + %{!mno-cygwin:-lcygwin} \ + %{mno-cygwin:%{mthreads:-lmingwthrd} -lmingw32} \ + %{mwindows:-lgdi32 -lcomdlg32} \ + -luser32 -lkernel32 -ladvapi32 -lshell32" + +#define LINK_SPEC W32API_LIB "\ + %{mwindows:--subsystem windows} \ + %{mconsole:--subsystem console} \ + %{shared: %{mdll: %eshared and mdll are not compatible}} \ + %{shared: --shared} %{mdll:--dll} \ + %{static:-Bstatic} %{!static:-Bdynamic} \ + %{shared|mdll: -e \ + %{mno-cygwin:_DllMainCRTStartup@12} \ + %{!mno-cygwin:__cygwin_dll_entry@12}}\ + --dll-search-prefix=cyg" + +#undef MATH_LIBRARY +#define MATH_LIBRARY "" #define SIZE_TYPE "unsigned int" #define PTRDIFF_TYPE "int" @@ -127,33 +183,12 @@ Boston, MA 02111-1307, USA. */ #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)) +union tree_node; +#define TREE union tree_node * /* Used to implement dllexport overriding dllimport semantics. It's also used to handle vtables - the first pass won't do anything because @@ -161,7 +196,7 @@ extern union tree_node *i386_pe_merge_decl_attributes (); It's also used to handle dllimport override semantics. */ #if 0 #define REDO_SECTION_INFO_P(DECL) \ - ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \ + ((DECL_ATTRIBUTES (DECL) != NULL_TREE) \ || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL))) #else #define REDO_SECTION_INFO_P(DECL) 1 @@ -169,37 +204,13 @@ extern union tree_node *i386_pe_merge_decl_attributes (); #undef EXTRA_SECTIONS -#define EXTRA_SECTIONS in_ctor, in_dtor, in_drectve +#define EXTRA_SECTIONS 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 () \ @@ -210,6 +221,7 @@ drectve_section () \ in_section = in_drectve; \ } \ } +void drectve_section PARAMS ((void)); /* Switch to SECTION (an `enum in_section'). @@ -218,6 +230,7 @@ drectve_section () \ ASM_DECLARE_OBJECT_NAME and then switch back to the original section afterwards. */ #define SWITCH_TO_SECTION_FUNCTION \ +void switch_to_section PARAMS ((enum in_section, tree)); \ void \ switch_to_section (section, decl) \ enum in_section section; \ @@ -228,31 +241,13 @@ switch_to_section (section, decl) \ 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. */ + otherwise. */ #undef SUBTARGET_OVERRIDE_OPTIONS #define SUBTARGET_OVERRIDE_OPTIONS \ @@ -282,7 +277,7 @@ do { \ 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 (); +extern void i386_pe_encode_section_info PARAMS ((TREE)); #ifdef ENCODE_SECTION_INFO #undef ENCODE_SECTION_INFO @@ -291,7 +286,9 @@ extern void i386_pe_encode_section_info (); /* Utility used only in this file. */ #define I386_PE_STRIP_ENCODING(SYM_NAME) \ - ((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) + ((SYM_NAME) + ((SYM_NAME)[0] == '@' \ + ? ((SYM_NAME)[3] == '*' ? 4 : 3) : 0) \ + + ((SYM_NAME)[0] == '*' ? 1 : 0)) /* This macro gets just the user-specified name out of the string in a SYMBOL_REF. Discard @@ -299,16 +296,17 @@ extern void i386_pe_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); \ + const char *_p; \ + const 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'; \ + char *_new_name = (char *) alloca (_len + 1); \ + strncpy (_new_name, _name, _len); \ + _new_name[_len] = '\0'; \ + (VAR) = _new_name; \ } \ else \ (VAR) = _name; \ @@ -319,14 +317,14 @@ do { \ #undef ASM_OUTPUT_LABELREF #define ASM_OUTPUT_LABELREF(STREAM, NAME) \ fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, \ - I386_PE_STRIP_ENCODING (NAME)) \ + 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)) \ - i386_pe_record_exported_symbol (NAME); \ + i386_pe_record_exported_symbol (NAME, 1); \ if (! i386_pe_dllimport_name_p (NAME)) \ { \ fprintf ((STREAM), "\t.comm\t"); \ @@ -341,21 +339,21 @@ do { \ #define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) \ do { \ if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME); \ + i386_pe_record_exported_symbol (NAME, 1); \ ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ } while (0) /* Emit code to check the stack when allocating more that 4000 - bytes in one go. */ + 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 +#undef TARGET_SUBTARGET_DEFAULT -#define TARGET_DEFAULT \ +#define TARGET_SUBTARGET_DEFAULT \ (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE) /* This is how to output an assembler line @@ -372,62 +370,16 @@ do { \ 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 (); +extern void i386_pe_unique_section PARAMS ((TREE, int)); #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) +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION i386_pe_asm_named_section + +/* Select attributes for named sections. */ +#define TARGET_SECTION_TYPE_FLAGS i386_pe_section_type_flags /* Write the extra assembler code needed to declare a function properly. If we are generating SDB debugging information, this @@ -437,7 +389,7 @@ do { \ do \ { \ if (i386_pe_dllexport_name_p (NAME)) \ - i386_pe_record_exported_symbol (NAME); \ + i386_pe_record_exported_symbol (NAME, 0); \ if (write_symbols != SDB_DEBUG) \ i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ ASM_OUTPUT_LABEL (FILE, NAME); \ @@ -458,53 +410,40 @@ do { \ #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ i386_pe_declare_function_type (FILE, XSTR (FUN, 0), 1) +/* This says out to put a global symbol in the BSS section. */ +#undef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) + /* Output function declarations at the end of the file. */ +#undef ASM_FILE_END #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. */ +/* 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) \ + if (current_function_profile \ + && MAIN_NAME_P (DECL_NAME (current_function_decl))) \ { \ - 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); \ + emit_call_insn (gen_rtx (CALL, VOIDmode, \ + gen_rtx_MEM (FUNCTION_MODE, \ + gen_rtx_SYMBOL_REF (Pmode, "_monstartup")), \ + const0_rtx)); \ } /* 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_record_exported_symbol PROTO((char *)); -extern void i386_pe_asm_file_end STDIO_PROTO((FILE *)); +extern void i386_pe_record_external_function PARAMS ((const char *)); +extern void i386_pe_declare_function_type PARAMS ((FILE *, const char *, int)); +extern void i386_pe_record_exported_symbol PARAMS ((const char *, int)); +extern void i386_pe_asm_file_end PARAMS ((FILE *)); +extern int i386_pe_dllexport_name_p PARAMS ((const char *)); +extern int i386_pe_dllimport_name_p PARAMS ((const char *)); /* For Win32 ABI compatibility */ #undef DEFAULT_PCC_STRUCT_RETURN @@ -514,12 +453,41 @@ extern void i386_pe_asm_file_end STDIO_PROTO((FILE *)); #undef BIGGEST_ALIGNMENT #define BIGGEST_ALIGNMENT 128 +/* Native complier aligns internal doubles in structures on dword boundaries. */ +#undef BIGGEST_FIELD_ALIGNMENT +#define BIGGEST_FIELD_ALIGNMENT 64 + /* A bitfield declared as `int' forces `int' alignment for the struct. */ -#undef PCC_BITFIELDS_TYPE_MATTERS -#define PCC_BITFIELDS_TYPE_MATTERS 0 +#undef PCC_BITFIELD_TYPE_MATTERS +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define GROUP_BITFIELDS_BY_ALIGN TYPE_NATIVE(rec) + /* Enable alias attribute support. */ #ifndef SET_ASM_OP -#define SET_ASM_OP "\t.set" +#define SET_ASM_OP "\t.set\t" #endif +/* Override GCC's relative pathname lookup (ie., relocatability) unless + otherwise told by other subtargets. */ +#ifndef WIN32_NO_ABSOLUTE_INST_DIRS +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/usr/lib/" + +#undef STANDARD_STARTFILE_PREFIX +#define STANDARD_STARTFILE_PREFIX "/usr/lib/mingw/" + +#ifndef CROSS_COMPILE +#undef LOCAL_INCLUDE_DIR +#undef TOOL_INCLUDE_DIR +#undef SYSTEM_INCLUDE_DIR +#undef STANDARD_INCLUDE_DIR +#define STANDARD_INCLUDE_DIR 0 +#endif /* not CROSS_COMPILE */ +#endif /* not WIN32_NO_ABSOLUTE_INST_DIRS */ + +#undef TREE + +#ifndef BUFSIZ +# undef FILE +#endif diff --git a/contrib/gcc/config/i386/dgux.h b/contrib/gcc/config/i386/dgux.h index 9e41d65..2d4c98c 100644 --- a/contrib/gcc/config/i386/dgux.h +++ b/contrib/gcc/config/i386/dgux.h @@ -1,5 +1,6 @@ /* Target definitions for GNU compiler for Intel 80x86 running DG/ux - Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1993, 1995, 1996, 1997, 1998, 2000, 2001 + Free Software Foundation, Inc. Currently maintained by gcc@dg-rtp.dg.com. This file is part of GNU CC. @@ -23,10 +24,8 @@ Boston, MA 02111-1307, USA. */ few hacks */ -#include "i386/sysv4.h" - #ifndef VERSION_INFO2 -#define VERSION_INFO2 "$Revision: 1.6 $" +#define VERSION_INFO2 "$Revision: 1.16 $" #endif #ifndef VERSION_STRING @@ -57,12 +56,17 @@ Boston, MA 02111-1307, USA. */ #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" }, + { "standard", MASK_STANDARD, \ + N_("Retain standard MXDB information") }, \ + { "legend", -MASK_NOLEGEND, \ + N_("Retain legend information") }, \ + { "no-legend", MASK_NOLEGEND, "" }, \ + { "external-legend", MASK_EXTERNAL_LEGEND, \ + N_("Generate external legend information") }, \ + { "identify-revision", MASK_IDENTIFY_REVISION, \ + N_("Emit identifying info in .s file") }, \ + { "warn-passed-structs", MASK_WARN_PASS_STRUCT, \ + N_("Warn when a function arg is a structure") }, #undef DWARF_DEBUGGING_INFO #define DWARF_DEBUGGING_INFO @@ -74,13 +78,18 @@ Boston, MA 02111-1307, USA. */ #undef DBX_DEBUGGING_INFO #define DBX_DEBUGGING_INFO +#undef PREFERRED_DEBUGGING_TYPE #define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG -/* Override svr[34].h. */ +/* Override svr[34].h. Switch to the data section so that the coffsem + symbol isn't in the text section. */ #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]) + do { \ + output_file_directive (FILE, main_input_filename); \ + fprintf (FILE, "\t.version\t\"01.01\"\n"); \ + data_section (); \ + } while (0) /* ix86 abi specified type for wchar_t */ @@ -144,15 +153,15 @@ Boston, MA 02111-1307, USA. */ 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)" +#define CPP_PREDEFINES "-D__ix86 -Dunix -DDGUX -D__CLASSIFY_TYPE__=2\ + -Asystem=unix -Asystem=svr4" /* 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__}}" +#define CPP_SPEC "%(cpp_cpu) %{!ansi:%{!traditional:-D__OPEN_NAMESPACE__}}" /* Assembler support (legends for mxdb). */ #undef ASM_SPEC @@ -207,8 +216,8 @@ Boston, MA 02111-1307, USA. */ #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}} \ + %{!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} \ @@ -226,9 +235,9 @@ Boston, MA 02111-1307, USA. */ /* Must use data section for relocatable constants when pic. */ #undef SELECT_RTX_SECTION -#define SELECT_RTX_SECTION(MODE,RTX) \ +#define SELECT_RTX_SECTION(MODE,RTX,ALIGN) \ { \ - if (flag_pic && symbolic_operand (RTX)) \ + if (flag_pic && symbolic_operand (RTX, VOIDmode)) \ data_section (); \ else \ const_section (); \ @@ -245,4 +254,4 @@ Boston, MA 02111-1307, USA. */ /* 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" +#define CONST_SECTION_ASM_OP "\t.section\t.rodata\n\t.align 1" diff --git a/contrib/gcc/config/i386/djgpp-rtems.h b/contrib/gcc/config/i386/djgpp-rtems.h index b355cc5..b8f4908 100644 --- a/contrib/gcc/config/i386/djgpp-rtems.h +++ b/contrib/gcc/config/i386/djgpp-rtems.h @@ -28,9 +28,8 @@ Boston, MA 02111-1307, USA. */ #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)" +#define CPP_PREDEFINES "-Dunix -DGO32 -DDJGPP=2 -DMSDOS \ + -Asystem=unix -Asystem=msdos -Asystem=rtems" /* Generate calls to memcpy, memcmp and memset. */ #ifndef TARGET_MEM_FUNCTIONS diff --git a/contrib/gcc/config/i386/djgpp.h b/contrib/gcc/config/i386/djgpp.h index 5727b0a..600a11e 100644 --- a/contrib/gcc/config/i386/djgpp.h +++ b/contrib/gcc/config/i386/djgpp.h @@ -1,5 +1,5 @@ /* Configuration for an i386 running MS-DOS with DJGPP. - Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -18,10 +18,12 @@ 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. */ +/* Support generation of DWARF2 debugging info. */ +#define DWARF2_DEBUGGING_INFO + +/* Don't assume anything about the header files. */ #define NO_IMPLICIT_EXTERN_C #define HANDLE_SYSV_PRAGMA @@ -33,24 +35,62 @@ Boston, MA 02111-1307, USA. */ #include "i386/gas.h" +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as + uninitialized global data. If not defined, and neither + `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, + uninitialized global data will be output in the data section if + `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be + used. */ +#undef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP "\t.section\t.bss" + +/* Define the name of the .data section. */ +#undef DATA_SECTION_ASM_OP +#define DATA_SECTION_ASM_OP "\t.section .data" + +/* Define the name of the .ident op. */ +#undef IDENT_ASM_OP +#define IDENT_ASM_OP "\t.ident\t" + /* Enable alias attribute support. */ #ifndef SET_ASM_OP -#define SET_ASM_OP "\t.set" +#define SET_ASM_OP "\t.set\t" #endif -/* Search for as.exe and ld.exe in DJGPP's binary directory. */ -#define MD_EXEC_PREFIX "$DJDIR/bin/" +/* Define the name of the .text section. */ +#undef TEXT_SECTION_ASM_OP +#define TEXT_SECTION_ASM_OP "\t.section .text" + +/* Define standard DJGPP installation paths. */ +/* We override default /usr or /usr/local part with /dev/env/DJDIR which */ +/* points to actual DJGPP instalation directory. */ + +/* Standard include directory */ +#undef STANDARD_INCLUDE_DIR +#define STANDARD_INCLUDE_DIR "/dev/env/DJDIR/include/" + +/* Search for as.exe and ld.exe in DJGPP's binary directory. */ +#undef MD_EXEC_PREFIX +#define MD_EXEC_PREFIX "/dev/env/DJDIR/bin/" + +/* Standard DJGPP library and startup files */ +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/dev/env/DJDIR/lib/" /* 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)" +#define CPP_PREDEFINES "-D__MSDOS__ -D__GO32__ -Asystem=msdos" + +/* Include <sys/version.h> so __DJGPP__ and __DJGPP_MINOR__ are defined. */ +#undef CPP_SPEC +#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ + %{!ansi:%{!std=c*:%{!std=i*:-DMSDOS}}} %{!ansi:%{!std=c*:%{!std=i*:-DGO32}}} \ + -imacros %s../include/sys/version.h" /* 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 @@ -83,57 +123,8 @@ Boston, MA 02111-1307, USA. */ 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) +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION default_coff_asm_named_section /* Output at beginning of assembler file. */ /* The .file command should always begin the output. */ @@ -152,10 +143,100 @@ dtor_section () \ #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 +/* This is how to output a global symbol in the BSS section. */ +#undef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN)) + +/* This is how to tell assembler that a symbol is weak */ +#undef ASM_WEAKEN_LABEL +#define ASM_WEAKEN_LABEL(FILE,NAME) \ + do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \ + fputc ('\n', FILE); } while (0) /* djgpp automatically calls its own version of __main, so don't define one in libgcc, nor call one in main(). */ #define HAS_INIT_SECTION + +/* Definitions for types and sizes. Wide characters are 16-bits long so + Win32 compiler add-ons will be wide character compatible. */ +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 1 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 16 + +#undef WCHAR_TYPE +#define WCHAR_TYPE "short unsigned int" + +#undef WINT_TYPE +#define WINT_TYPE "int" + +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +/* Used to be defined in xm-djgpp.h, but moved here for cross-compilers. */ +#define LIBSTDCXX "-lstdcxx" + +/* -mbnu210 is now ignored and obsolete. It was used to enable support for + weak symbols, and .gnu.linkonce support. */ +#undef MASK_BNU210 +#define MASK_BNU210 (0x40000000) + +#undef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES \ + { "no-bnu210", -MASK_BNU210, "Ignored (obsolete)" }, \ + { "bnu210", MASK_BNU210, "Ignored (obsolete)" }, + +/* Warn that -mbnu210 is now obsolete. */ +#undef SUBTARGET_OVERRIDE_OPTIONS +#define SUBTARGET_OVERRIDE_OPTIONS \ +do \ + { \ + if (target_flags & MASK_BNU210) \ + { \ + warning ("-mbnu210 is ignored (option is obsolete)"); \ + } \ + } \ +while (0) + +/* Support for C++ templates. */ +#undef MAKE_DECL_ONE_ONLY +#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) + +#undef UNIQUE_SECTION +#define UNIQUE_SECTION(DECL,RELOC) \ +do { \ + int len; \ + const char *name, *prefix; \ + char *string; \ + \ + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ + /* Strip off any encoding in fnname. */ \ + STRIP_NAME_ENCODING (name, name); \ + \ + if (! DECL_ONE_ONLY (DECL)) \ + { \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".text."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".rodata."; \ + else \ + prefix = ".data."; \ + } \ + else if (TREE_CODE (DECL) == FUNCTION_DECL) \ + prefix = ".gnu.linkonce.t."; \ + else if (DECL_READONLY_SECTION (DECL, RELOC)) \ + prefix = ".gnu.linkonce.r."; \ + else \ + prefix = ".gnu.linkonce.d."; \ + \ + len = strlen (name) + strlen (prefix); \ + string = alloca (len + 1); \ + sprintf (string, "%s%s", prefix, name); \ + \ + DECL_SECTION_NAME (DECL) = build_string (len, string); \ +} while (0) diff --git a/contrib/gcc/config/i386/freebsd-aout.h b/contrib/gcc/config/i386/freebsd-aout.h index 89fe216..0a3c6d7 100644 --- a/contrib/gcc/config/i386/freebsd-aout.h +++ b/contrib/gcc/config/i386/freebsd-aout.h @@ -1,6 +1,7 @@ /* Definitions of target machine for GNU compiler for Intel 80386 running FreeBSD. - Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2002 Free Software + Foundation, Inc. Contributed by Poul-Henning Kamp <phk@login.dkuug.dk> This file is part of GNU CC. @@ -23,21 +24,26 @@ Boston, MA 02111-1307, USA. */ /* This is tested by i386gas.h. */ #define YES_UNDERSCORES -/* Don't assume anything about the header files. */ +/* 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 \ +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT \ (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_NO_FANCY_MATH_387) +/* The macro defined in i386.h doesn't work with the old gas of + FreeBSD 2.x. The definition in sco.h and sol2.h appears to work, + but it turns out that, even though the assembler doesn't complain, + we get incorrect results. Fortunately, the definition in + defaults.h works. */ +#undef ASM_PREFERRED_EH_DATA_FORMAT + #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-Dunix -D__FreeBSD__\ + -Asystem=unix -Asystem=bsd -Asystem=FreeBSD" /* Like the default, except no -lg. */ #define LIB_SPEC "%{!shared:%{!pg:-lc}%{pg:-lc_p}}" @@ -56,8 +62,6 @@ Boston, MA 02111-1307, USA. */ #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE BITS_PER_WORD -#define HAVE_ATEXIT - /* Override the default comment-starter of "/". */ #undef ASM_COMMENT_START @@ -72,28 +76,12 @@ Boston, MA 02111-1307, USA. */ /* 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. */ + libraries compiled with the native cc. */ #undef NO_DOLLAR_IN_LABEL /* i386 freebsd still uses old binutils that don't insert nops by default @@ -133,8 +121,8 @@ Boston, MA 02111-1307, USA. */ 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 TYPE_ASM_OP "\t.type\t" +#define SIZE_ASM_OP "\t.size\t" /* The following macro defines the format used to output the second operand of the .type assembler directive. Different svr4 assemblers @@ -163,7 +151,7 @@ Boston, MA 02111-1307, USA. */ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ do { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "%s", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ @@ -176,7 +164,7 @@ Boston, MA 02111-1307, USA. */ #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ do { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "%s", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ @@ -185,7 +173,7 @@ Boston, MA 02111-1307, USA. */ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ { \ size_directive_output = 1; \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, NAME); \ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ } \ @@ -200,13 +188,13 @@ Boston, MA 02111-1307, USA. */ #define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ do { \ - char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + const 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); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, name); \ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\ } \ @@ -224,7 +212,7 @@ do { \ labelno++; \ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, (FNAME)); \ fprintf (FILE, ","); \ assemble_name (FILE, label); \ @@ -245,3 +233,10 @@ do { \ #define STARTFILE_SPEC \ "%{shared:c++rt0.o%s} \ %{!shared:%{pg:gcrt0.o%s}%{!pg:%{static:scrt0.o%s}%{!static:crt0.o%s}}}" + +/* Define this so we can compile MS code for use with WINE. */ +#define HANDLE_PRAGMA_PACK_PUSH_POP + +/* FreeBSD 2.2.7's assembler does not support .quad properly. Do not + use it. */ +#undef ASM_QUAD diff --git a/contrib/gcc/config/i386/freebsd.h b/contrib/gcc/config/i386/freebsd.h index e97d4ca..142e6f2 100644 --- a/contrib/gcc/config/i386/freebsd.h +++ b/contrib/gcc/config/i386/freebsd.h @@ -1,5 +1,5 @@ /* Definitions for Intel 386 running FreeBSD with ELF format - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 2000 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. @@ -25,20 +25,6 @@ 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 - -/* Use more efficient ``thunks'' to implement C++ vtables. */ -#undef DEFAULT_VTABLE_THUNKS -#define DEFAULT_VTABLE_THUNKS 1 - /* Override the default comment-starter of "/". */ #undef ASM_COMMENT_START #define ASM_COMMENT_START "#" @@ -50,90 +36,14 @@ Boston, MA 02111-1307, USA. */ #define ASM_APP_OFF "#NO_APP\n" #undef SET_ASM_OP -#define SET_ASM_OP ".set" - -/* 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) +#define SET_ASM_OP "\t.set\t" -/* Indicate that jump tables go in the text section. This is - necessary when compiling PIC code. */ -#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) - -/* Use stabs instead of DWARF debug format. */ -#undef PREFERRED_DEBUGGING_TYPE -#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG - -/* 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)) + (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) + +#undef NO_PROFILE_COUNTERS +#define NO_PROFILE_COUNTERS /* Tell final.c that we don't need a label passed to mcount. */ @@ -141,48 +51,26 @@ Boston, MA 02111-1307, USA. */ #define FUNCTION_PROFILER(FILE, LABELNO) \ { \ if (flag_pic) \ - fprintf (FILE, "\tcall *.mcount@GOT(%%ebx)\n"); \ + fprintf ((FILE), "\tcall *.mcount@GOT(%%ebx)\n"); \ else \ - fprintf (FILE, "\tcall .mcount\n"); \ + fprintf ((FILE), "\tcall .mcount\n"); \ } +/* Make gcc agree with <machine/ansi.h>. */ + #undef SIZE_TYPE #define SIZE_TYPE "unsigned int" #undef PTRDIFF_TYPE #define PTRDIFF_TYPE "int" -#undef WCHAR_TYPE -#define WCHAR_TYPE "int" - -#undef WCHAR_UNSIGNED -#define WCHAR_UNSIGNED 0 - #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE 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}" - -/* This defines which switch letters take arguments. On FreeBSD, most of - the normal cases (defined in gcc.c) apply, and we also have -h* and - -z* options (for the linker) (comming from svr4). - We also have -R (alias --rpath), no -z, --soname (-h), --assert etc. */ - -#undef SWITCH_TAKES_ARG -#define SWITCH_TAKES_ARG(CHAR) \ - (DEFAULT_SWITCH_TAKES_ARG (CHAR) \ - || (CHAR) == 'h' \ - || (CHAR) == 'z' \ - || (CHAR) == 'R') - /* Provide a STARTFILE_SPEC appropriate for FreeBSD. Here we add the magical crtbegin.o file (see crtstuff.c) which provides part of the support for getting C++ file-scope static object constructed - before entering `main'. */ + before entering `main'. */ #undef STARTFILE_SPEC #define STARTFILE_SPEC \ @@ -202,19 +90,6 @@ Boston, MA 02111-1307, USA. */ #define ENDFILE_SPEC \ "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" -/* Provide a LIB_SPEC appropriate for FreeBSD. Just select the appropriate - libc, depending on whether we're doing profiling or need threads support. - (simular to the default, except no -lg, and no -p. */ - -#undef LIB_SPEC -#define LIB_SPEC "%{!shared: \ - %{!pg:%{!pthread:%{!kthread:-lc} \ - %{kthread:-lpthread -lc}} \ - %{pthread:-lc_r}} \ - %{pg:%{!pthread:%{!kthread:-lc_p} \ - %{kthread:-lpthread_p -lc_p}} \ - %{pthread:-lc_r_p}}}" - /* 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 @@ -249,9 +124,9 @@ Boston, MA 02111-1307, USA. */ 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)); \ +#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/contrib/gcc/config/i386/freebsd64.h b/contrib/gcc/config/i386/freebsd64.h new file mode 100644 index 0000000..ebd6618 --- /dev/null +++ b/contrib/gcc/config/i386/freebsd64.h @@ -0,0 +1,43 @@ +/* Definitions for AMD x86-64 running FreeBSD with ELF format + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by David O'Brien <obrien@FreeBSD.org> + +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, " (FreeBSD/x86-64 ELF)"); + +/* Provide a LINK_SPEC appropriate for the FreeBSD/x86-64 ELF target. + This is a copy of LINK_SPEC from <i386/freebsd.h> tweaked for + the x86-64 target. */ + +#undef LINK_SPEC +#define LINK_SPEC "\ + %{!m32:-m elf_x86_64} \ + %{m32:-m elf_i386} \ + %{Wl,*:%*} \ + %{v:-V} \ + %{assert*} %{R*} %{rpath*} %{defsym*} \ + %{shared:-Bshareable %{h*} %{soname*}} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \ + %{static:-Bstatic}} \ + %{symbolic:-Bsymbolic}" diff --git a/contrib/gcc/config/i386/gas.h b/contrib/gcc/config/i386/gas.h index 4ce1891..6c01b07 100644 --- a/contrib/gcc/config/i386/gas.h +++ b/contrib/gcc/config/i386/gas.h @@ -19,7 +19,7 @@ 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. */ + file. */ #include "i386/i386.h" @@ -131,12 +131,12 @@ Boston, MA 02111-1307, USA. */ count is in %cl. Some assemblers require %cl as an argument; some don't. - GAS requires the %cl argument, so override i386/unix.h. */ + 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. */ +/* Print opcodes the way that GAS expects them. */ #define GAS_MNEMONICS 1 #ifdef NO_UNDERSCORES /* If user-symbols don't have underscores, @@ -150,7 +150,7 @@ Boston, MA 02111-1307, USA. */ #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), ".%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), ".%s%ld", (PREFIX), (long)(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. */ @@ -160,3 +160,13 @@ Boston, MA 02111-1307, USA. */ fprintf (FILE, ".%s%d:\n", PREFIX, NUM) #endif /* NO_UNDERSCORES */ + +/* Output at beginning of assembler file. */ +/* The .file command should always begin the output. */ +#undef ASM_FILE_START +#define ASM_FILE_START(FILE) \ + do { \ + if (ix86_asm_dialect == ASM_INTEL) \ + fputs ("\t.intel_syntax\n", FILE); \ + output_file_directive (FILE, main_input_filename); \ + } while (0) diff --git a/contrib/gcc/config/i386/gmon-sol2.c b/contrib/gcc/config/i386/gmon-sol2.c index 35ac1c9..8ea242b 100644 --- a/contrib/gcc/config/i386/gmon-sol2.c +++ b/contrib/gcc/config/i386/gmon-sol2.c @@ -10,10 +10,7 @@ * 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. + * 3. [rescinded 22 July 1999] * 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. diff --git a/contrib/gcc/config/i386/gnu.h b/contrib/gcc/config/i386/gnu.h index cd32b92..0214c05 100644 --- a/contrib/gcc/config/i386/gnu.h +++ b/contrib/gcc/config/i386/gnu.h @@ -1,17 +1,11 @@ /* Configuration for an i386 running GNU with ELF as the target machine. */ -/* This does it mostly for us. */ -#include <i386/linux.h> - -/* Get machine-independent configuration parameters for the GNU system. */ -#include <gnu.h> - #undef TARGET_VERSION #define TARGET_VERSION fprintf (stderr, " (i386 GNU)"); #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-D__ELF__ -D__i386__ -DMACH -Asystem(mach) \ - -Dunix -Asystem(unix) -Asystem(posix) -D__GNU__ -Asystem(gnu)" +#define CPP_PREDEFINES "-D__ELF__ -DMACH -Asystem=mach \ + -Dunix -Asystem=unix -Asystem=posix -D__GNU__ -Asystem=gnu" #undef CPP_SPEC #define CPP_SPEC "%(cpp_cpu) \ @@ -35,4 +29,8 @@ %{!static: \ %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}} \ %{static:crt0.o%s}} \ - crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}" + crti.o%s %{static:crtbeginT.o%s}\ + %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}" + +/* FIXME: Is a Hurd-specific fallback mechanism necessary? */ +#undef MD_FALLBACK_FRAME_STATE_FOR diff --git a/contrib/gcc/config/i386/i386-aout.h b/contrib/gcc/config/i386/i386-aout.h index e4be8d5..7385bec 100644 --- a/contrib/gcc/config/i386/i386-aout.h +++ b/contrib/gcc/config/i386/i386-aout.h @@ -29,6 +29,6 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Di386" +#define CPP_PREDEFINES "" /* end of i386-aout.h */ diff --git a/contrib/gcc/config/i386/i386-coff.h b/contrib/gcc/config/i386/i386-coff.h index 2e00b7a..c1ae670 100644 --- a/contrib/gcc/config/i386/i386-coff.h +++ b/contrib/gcc/config/i386/i386-coff.h @@ -1,7 +1,7 @@ /* Definitions for "naked" Intel 386 using coff object format files and coff debugging info. - Copyright (C) 1994 Free Software Foundation, Inc. + Copyright (C) 1994, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -27,7 +27,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Di386" +#define CPP_PREDEFINES "" /* We want to be able to get DBX debugging information via -gstabs. */ @@ -37,67 +37,7 @@ Boston, MA 02111-1307, USA. */ #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) - +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION default_coff_asm_named_section /* end of i386-coff.h */ diff --git a/contrib/gcc/config/i386/i386-interix.h b/contrib/gcc/config/i386/i386-interix.h index 8e9f443..962862f 100644 --- a/contrib/gcc/config/i386/i386-interix.h +++ b/contrib/gcc/config/i386/i386-interix.h @@ -1,5 +1,5 @@ /* Target definitions for GNU compiler for Intel 80386 running Interix - Parts Copyright (C) 1991, 1999 Free Software Foundation, Inc. + Parts Copyright (C) 1991, 1999, 2000 Free Software Foundation, Inc. Parts: by Douglas B. Rupp (drupp@cs.washington.edu). @@ -26,9 +26,9 @@ Boston, MA 02111-1307, USA. */ #define YES_UNDERSCORES -/* YES_UNDERSCORES must preceed gas.h */ +/* YES_UNDERSCORES must precede gas.h */ #include <i386/gas.h> -/* The rest must follow. */ +/* The rest must follow. */ #define DBX_DEBUGGING_INFO #define SDB_DEBUGGING_INFO @@ -39,9 +39,9 @@ Boston, MA 02111-1307, USA. */ /* 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 \ + We also align doubles to 64-bits for MSVC default compatibility */ +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT \ (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE | \ MASK_ALIGN_DOUBLE) @@ -57,9 +57,6 @@ Boston, MA 02111-1307, USA. */ #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 " \ @@ -68,7 +65,7 @@ Boston, MA 02111-1307, USA. */ -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)" + -Asystem=unix -Asystem=interix" #undef CPP_SPEC /* Write out the correct language type definition for the header files. @@ -86,14 +83,14 @@ Boston, MA 02111-1307, USA. */ -remap \ %(cpp_cpu) \ %{posix:-D_POSIX_SOURCE} \ --idirafter %$INTERIX_ROOT/usr/include" +-isystem %$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. */ + is kind of hard to detect, we just do it all the time. */ #ifdef ASM_FILE_START #undef ASM_FILE_START @@ -143,7 +140,7 @@ Boston, MA 02111-1307, USA. */ #define STRING_LIMIT ((unsigned) 256) -#define STRING_ASM_OP ".string" +#define STRING_ASM_OP "\t.string\t" /* The routine used to output NUL terminated strings. We use a special version of this for most svr4 targets because doing so makes the @@ -155,9 +152,10 @@ Boston, MA 02111-1307, USA. */ #define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ do \ { \ - register unsigned char *_limited_str = (unsigned char *) (STR); \ + register const unsigned char *_limited_str = \ + (const unsigned char *) (STR); \ register unsigned ch; \ - fprintf ((FILE), "\t%s\t\"", STRING_ASM_OP); \ + fprintf ((FILE), "%s\"", STRING_ASM_OP); \ for (; (ch = *_limited_str); _limited_str++) \ { \ register int escape = ESCAPES[ch]; \ @@ -190,12 +188,13 @@ Boston, MA 02111-1307, USA. */ #define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ do \ { \ - register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ - register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register const unsigned char *_ascii_bytes = \ + (const unsigned char *) (STR); \ + register const unsigned char *limit = _ascii_bytes + (LENGTH); \ register unsigned bytes_in_chunk = 0; \ for (; _ascii_bytes < limit; _ascii_bytes++) \ { \ - register unsigned char *p; \ + register const unsigned char *p; \ if (bytes_in_chunk >= 64) \ { \ fputc ('\n', (FILE)); \ @@ -203,7 +202,7 @@ Boston, MA 02111-1307, USA. */ } \ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ continue; \ - if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + if (p < limit && (p - _ascii_bytes) <= (long) STRING_LIMIT) \ { \ if (bytes_in_chunk > 0) \ { \ @@ -228,23 +227,8 @@ Boston, MA 02111-1307, USA. */ } \ 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. */ + bytes in one go. */ #define CHECK_STACK_LIMIT 0x1000 @@ -254,10 +238,7 @@ Boston, MA 02111-1307, USA. */ #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 +/* 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 @@ -266,25 +247,7 @@ Boston, MA 02111-1307, USA. */ #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\"" +#define CONST_SECTION_ASM_OP "\t.section\t.rdata,\"r\"" /* 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 @@ -292,7 +255,7 @@ Boston, MA 02111-1307, USA. */ includes this file. */ #undef EXTRA_SECTIONS -#define EXTRA_SECTIONS in_const, in_ctors, in_dtors +#define EXTRA_SECTIONS in_const /* A default list of extra section function definitions. For targets that use additional sections (e.g. .tdesc) you should override this @@ -300,15 +263,11 @@ Boston, MA 02111-1307, USA. */ #undef EXTRA_SECTION_FUNCTIONS #define EXTRA_SECTION_FUNCTIONS \ - CONST_SECTION_FUNCTION \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION + CONST_SECTION_FUNCTION #undef READONLY_DATA_SECTION #define READONLY_DATA_SECTION() const_section () -extern void text_section (); - #define CONST_SECTION_FUNCTION \ void \ const_section () \ @@ -322,85 +281,21 @@ const_section () \ } \ } -#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). */ + ld -r (specifically -rU). */ #define CTOR_LISTS_DEFINED_EXTERNALLY 1 -#define SET_ASM_OP ".set" +#define SET_ASM_OP "\t.set\t" /* Output a definition (implements alias) */ #define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ do \ { \ - fprintf ((FILE), "\t%s\t", SET_ASM_OP); \ + fprintf ((FILE), "%s", SET_ASM_OP); \ assemble_name (FILE, LABEL1); \ fprintf (FILE, ","); \ assemble_name (FILE, LABEL2); \ @@ -417,7 +312,7 @@ while (0) /* 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.... */ + problem, so.... */ /* Forward references to tags are allowed. */ #define SDB_ALLOW_FORWARD_REFERENCES @@ -435,7 +330,8 @@ while (0) #undef DBX_REGISTER_NUMBER #define DBX_REGISTER_NUMBER(n) \ -((n) == 0 ? 0 \ +(TARGET_64BIT ? dbx64_register_map[n] \ + : (n) == 0 ? 0 \ : (n) == 1 ? 2 \ : (n) == 2 ? 1 \ : (n) == 3 ? 3 \ @@ -452,9 +348,10 @@ while (0) Apply stddef, handle (as yet unimplemented) pic. - stddef renaming does NOT apply to Alpha. */ + stddef renaming does NOT apply to Alpha. */ -char *gen_stdcall_suffix (); +union tree_node; +const char *gen_stdcall_suffix PARAMS ((union tree_node *)); #undef ENCODE_SECTION_INFO #define ENCODE_SECTION_INFO(DECL) \ @@ -482,16 +379,17 @@ while (0) #undef STRIP_NAME_ENCODING #define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ do { \ - char *_p; \ - char *_name = SYMBOL_NAME; \ + const char *_p; \ + const 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'; \ + char *_new_name = (char *) alloca (_len + 1); \ + strncpy (_new_name, _name, _len); \ + _new_name[_len] = '\0'; \ + (VAR) = _new_name; \ } \ else \ (VAR) = _name; \ @@ -500,7 +398,7 @@ do { \ #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. */ + 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 @@ -508,68 +406,18 @@ do { \ 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) - +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION default_pe_asm_named_section #endif /* 0 */ -/* DWARF2 Unwinding doesn't work with exception handling yet. */ +/* DWARF2 Unwinding doesn't work with exception handling yet. */ #define DWARF2_UNWIND_INFO 0 -/* Don't assume anything about the header files. */ +/* Don't assume anything about the header files. */ #define NO_IMPLICIT_EXTERN_C diff --git a/contrib/gcc/config/i386/i386-interix3.h b/contrib/gcc/config/i386/i386-interix3.h new file mode 100644 index 0000000..274972b --- /dev/null +++ b/contrib/gcc/config/i386/i386-interix3.h @@ -0,0 +1,32 @@ +/* Target definitions for GNU compiler for Intel 80386 running Interix V3. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Douglas B. Rupp (rupp@gnat.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. */ + +#undef CPP_SPEC +#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} \ +%(cpp_cpu) \ +%{posix:-D_POSIX_SOURCE}" + diff --git a/contrib/gcc/config/i386/i386-protos.h b/contrib/gcc/config/i386/i386-protos.h new file mode 100644 index 0000000..01c4d44 --- /dev/null +++ b/contrib/gcc/config/i386/i386-protos.h @@ -0,0 +1,199 @@ +/* Definitions of target machine for GNU compiler for IA-32. + Copyright (C) 1988, 1992, 1994, 1995, 1996, 1996, 1997, 1998, 1999, + 2000, 2001 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. */ + +/* Functions in i386.c */ +extern void override_options PARAMS ((void)); +extern void optimization_options PARAMS ((int, int)); + +extern int ix86_can_use_return_insn_p PARAMS ((void)); +extern int ix86_frame_pointer_required PARAMS ((void)); +extern void ix86_setup_frame_addresses PARAMS ((void)); + +extern void ix86_asm_file_end PARAMS ((FILE *)); +extern void load_pic_register PARAMS ((void)); +extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int)); +extern void ix86_expand_prologue PARAMS ((void)); +extern void ix86_expand_epilogue PARAMS ((int)); + +extern void ix86_output_function_block_profiler PARAMS ((FILE *, int)); +extern void ix86_output_block_profiler PARAMS ((FILE *, int)); + +extern void ix86_output_addr_vec_elt PARAMS ((FILE *, int)); +extern void ix86_output_addr_diff_elt PARAMS ((FILE *, int, int)); + +#ifdef RTX_CODE +extern int ix86_aligned_p PARAMS ((rtx)); + +extern int standard_80387_constant_p PARAMS ((rtx)); +extern int standard_sse_constant_p PARAMS ((rtx)); +extern int symbolic_reference_mentioned_p PARAMS ((rtx)); + +extern int x86_64_general_operand PARAMS ((rtx, enum machine_mode)); +extern int x86_64_szext_general_operand PARAMS ((rtx, enum machine_mode)); +extern int x86_64_nonmemory_operand PARAMS ((rtx, enum machine_mode)); +extern int x86_64_szext_nonmemory_operand PARAMS ((rtx, enum machine_mode)); +extern int x86_64_immediate_operand PARAMS ((rtx, enum machine_mode)); +extern int x86_64_zext_immediate_operand PARAMS ((rtx, enum machine_mode)); +extern int const_int_1_operand PARAMS ((rtx, enum machine_mode)); +extern int symbolic_operand PARAMS ((rtx, enum machine_mode)); +extern int pic_symbolic_operand PARAMS ((rtx, enum machine_mode)); +extern int call_insn_operand PARAMS ((rtx, enum machine_mode)); +extern int constant_call_address_operand PARAMS ((rtx, enum machine_mode)); +extern int const0_operand PARAMS ((rtx, enum machine_mode)); +extern int const1_operand PARAMS ((rtx, enum machine_mode)); +extern int const248_operand PARAMS ((rtx, enum machine_mode)); +extern int incdec_operand PARAMS ((rtx, enum machine_mode)); +extern int reg_no_sp_operand PARAMS ((rtx, enum machine_mode)); +extern int mmx_reg_operand PARAMS ((rtx, enum machine_mode)); +extern int general_no_elim_operand PARAMS ((rtx, enum machine_mode)); +extern int nonmemory_no_elim_operand PARAMS ((rtx, enum machine_mode)); +extern int q_regs_operand PARAMS ((rtx, enum machine_mode)); +extern int non_q_regs_operand PARAMS ((rtx, enum machine_mode)); +extern int sse_comparison_operator PARAMS ((rtx, enum machine_mode)); +extern int fcmov_comparison_operator PARAMS ((rtx, enum machine_mode)); +extern int cmp_fp_expander_operand PARAMS ((rtx, enum machine_mode)); +extern int ix86_comparison_operator PARAMS ((rtx, enum machine_mode)); +extern int ext_register_operand PARAMS ((rtx, enum machine_mode)); +extern int binary_fp_operator PARAMS ((rtx, enum machine_mode)); +extern int mult_operator PARAMS ((rtx, enum machine_mode)); +extern int div_operator PARAMS ((rtx, enum machine_mode)); +extern int arith_or_logical_operator PARAMS ((rtx, enum machine_mode)); +extern int promotable_binary_operator PARAMS ((rtx, enum machine_mode)); +extern int memory_displacement_operand PARAMS ((rtx, enum machine_mode)); +extern int cmpsi_operand PARAMS ((rtx, enum machine_mode)); +extern int long_memory_operand PARAMS ((rtx, enum machine_mode)); +extern int aligned_operand PARAMS ((rtx, enum machine_mode)); +extern enum machine_mode ix86_cc_mode PARAMS ((enum rtx_code, rtx, rtx)); + +extern int ix86_expand_movstr PARAMS ((rtx, rtx, rtx, rtx)); +extern int ix86_expand_clrstr PARAMS ((rtx, rtx, rtx)); +extern int ix86_expand_strlen PARAMS ((rtx, rtx, rtx, rtx)); + +extern int legitimate_pic_address_disp_p PARAMS ((rtx)); +extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int)); +extern rtx legitimize_pic_address PARAMS ((rtx, rtx)); +extern rtx legitimize_address PARAMS ((rtx, rtx, enum machine_mode)); + +extern void print_reg PARAMS ((rtx, int, FILE*)); +extern void print_operand PARAMS ((FILE*, rtx, int)); +extern void print_operand_address PARAMS ((FILE*, rtx)); + +extern void split_di PARAMS ((rtx[], int, rtx[], rtx[])); +extern void split_ti PARAMS ((rtx[], int, rtx[], rtx[])); + +extern const char *output_387_binary_op PARAMS ((rtx, rtx*)); +extern const char *output_fix_trunc PARAMS ((rtx, rtx*)); +extern const char *output_fp_compare PARAMS ((rtx, rtx*, int, int)); + +extern void i386_dwarf_output_addr_const PARAMS ((FILE*, rtx)); +extern rtx i386_simplify_dwarf_addr PARAMS ((rtx)); + +extern void ix86_expand_clear PARAMS ((rtx)); +extern void ix86_expand_move PARAMS ((enum machine_mode, rtx[])); +extern void ix86_expand_vector_move PARAMS ((enum machine_mode, rtx[])); +extern void ix86_expand_binary_operator PARAMS ((enum rtx_code, + enum machine_mode, rtx[])); +extern int ix86_binary_operator_ok PARAMS ((enum rtx_code, enum machine_mode, + rtx[])); +extern void ix86_expand_unary_operator PARAMS ((enum rtx_code, enum machine_mode, + rtx[])); +extern int ix86_unary_operator_ok PARAMS ((enum rtx_code, enum machine_mode, + rtx[])); +extern int ix86_match_ccmode PARAMS ((rtx, enum machine_mode)); +extern rtx ix86_expand_compare PARAMS ((enum rtx_code, rtx *, rtx *)); +extern int ix86_use_fcomi_compare PARAMS ((enum rtx_code)); +extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx)); +extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx)); +extern int ix86_expand_int_movcc PARAMS ((rtx[])); +extern int ix86_expand_fp_movcc PARAMS ((rtx[])); +extern void x86_initialize_trampoline PARAMS ((rtx, rtx, rtx)); +extern rtx ix86_zero_extend_to_Pmode PARAMS ((rtx)); +extern void ix86_split_long_move PARAMS ((rtx[])); +extern void ix86_split_ashldi PARAMS ((rtx *, rtx)); +extern void ix86_split_ashrdi PARAMS ((rtx *, rtx)); +extern void ix86_split_lshrdi PARAMS ((rtx *, rtx)); +extern int ix86_address_cost PARAMS ((rtx)); +extern rtx ix86_find_base_term PARAMS ((rtx)); + +extern rtx assign_386_stack_local PARAMS ((enum machine_mode, int)); +extern int ix86_attr_length_immediate_default PARAMS ((rtx, int)); +extern int ix86_attr_length_address_default PARAMS ((rtx)); + +extern enum machine_mode ix86_fp_compare_mode PARAMS ((enum rtx_code)); + +extern int x86_64_sign_extended_value PARAMS ((rtx)); +extern int x86_64_zero_extended_value PARAMS ((rtx)); +extern rtx ix86_libcall_value PARAMS ((enum machine_mode)); +extern bool ix86_function_value_regno_p PARAMS ((int)); +extern bool ix86_function_arg_regno_p PARAMS ((int)); +extern int ix86_function_arg_boundary PARAMS ((enum machine_mode, tree)); +extern int ix86_return_in_memory PARAMS ((tree)); +extern void ix86_va_start PARAMS ((int, tree, rtx)); +extern rtx ix86_va_arg PARAMS ((tree, tree)); +extern void ix86_setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *, + enum machine_mode, + tree, int *, int)); + +extern rtx ix86_force_to_memory PARAMS ((enum machine_mode, rtx)); +extern void ix86_free_from_memory PARAMS ((enum machine_mode)); +extern void ix86_split_fp_branch PARAMS ((enum rtx_code code, rtx, + rtx, rtx, rtx, rtx)); +extern int ix86_hard_regno_mode_ok PARAMS ((int, enum machine_mode)); +extern int ix86_register_move_cost PARAMS ((enum machine_mode, enum reg_class, + enum reg_class)); +extern int ix86_secondary_memory_needed PARAMS ((enum reg_class, + enum reg_class, + enum machine_mode, int)); +extern enum reg_class ix86_preferred_reload_class PARAMS ((rtx, + enum reg_class)); +extern int ix86_memory_move_cost PARAMS ((enum machine_mode, enum reg_class, + int)); +extern void ix86_set_move_mem_attrs PARAMS ((rtx, rtx, rtx, rtx, rtx)); +extern void emit_i387_cw_initialization PARAMS ((rtx, rtx)); +extern bool ix86_fp_jump_nontrivial_p PARAMS ((enum rtx_code)); + + +#ifdef TREE_CODE +extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx)); +extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); +extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, + tree, int)); +extern rtx ix86_function_value PARAMS ((tree)); +extern void ix86_init_builtins PARAMS ((void)); +extern rtx ix86_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int)); +#endif + +#endif + +#ifdef TREE_CODE +extern int ix86_return_pops_args PARAMS ((tree, tree, int)); +extern tree ix86_build_va_list PARAMS ((void)); + +extern int ix86_data_alignment PARAMS ((tree, int)); +extern int ix86_local_alignment PARAMS ((tree, int)); +extern int ix86_constant_alignment PARAMS ((tree, int)); +extern tree ix86_handle_dll_attribute PARAMS ((tree *, tree, tree, int, bool *)); +extern tree ix86_handle_shared_attribute PARAMS ((tree *, tree, tree, int, bool *)); + +extern unsigned int i386_pe_section_type_flags PARAMS ((tree, const char *, + int)); +extern void i386_pe_asm_named_section PARAMS ((const char *, unsigned int)); +#endif diff --git a/contrib/gcc/config/i386/i386.c b/contrib/gcc/config/i386/i386.c index 0333b19..7eedba3 100644 --- a/contrib/gcc/config/i386/i386.c +++ b/contrib/gcc/config/i386/i386.c @@ -1,5 +1,6 @@ -/* Subroutines for insn-output.c for Intel X86. - Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc. +/* Subroutines used for code generation on IA-32. + Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -16,50 +17,75 @@ 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. */ +Boston, MA 02111-1307, USA. */ -#include <setjmp.h> #include "config.h" #include "system.h" #include "rtl.h" +#include "tree.h" +#include "tm_p.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 "optabs.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 +#include "basic-block.h" +#include "ggc.h" +#include "target.h" +#include "target-def.h" #ifndef CHECK_STACK_LIMIT -#define CHECK_STACK_LIMIT -1 +#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) */ +static const +struct processor_costs size_cost = { /* costs for tunning for size */ + 2, /* cost of an add instruction */ + 3, /* cost of a lea instruction */ + 2, /* variable shift costs */ + 3, /* constant shift costs */ + 3, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 3, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 3, /* cost of movzx */ + 0, /* "large" insn */ + 2, /* MOVE_RATIO */ + 2, /* cost for loading QImode using movzbl */ + {2, 2, 2}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 2, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {2, 2, 2}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {2, 2, 2}, /* cost of loading integer registers */ + 3, /* cost of moving MMX register */ + {3, 3}, /* cost of loading MMX registers + in SImode and DImode */ + {3, 3}, /* cost of storing MMX registers + in SImode and DImode */ + 3, /* cost of moving SSE register */ + {3, 3, 3}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {3, 3, 3}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 3, /* MMX or SSE register to integer */ + 0, /* size of prefetch block */ + 0, /* number of parallel prefetches */ }; - /* Processor costs (relative to an add) */ +static const struct processor_costs i386_cost = { /* 386 specific costs */ 1, /* cost of an add instruction */ 1, /* cost of a lea instruction */ @@ -67,9 +93,36 @@ struct processor_costs i386_cost = { /* 386 specific 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 */ + 23, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ + 15, /* "large" insn */ + 3, /* MOVE_RATIO */ + 4, /* cost for loading QImode using movzbl */ + {2, 4, 2}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 4, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {8, 8, 8}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {8, 8, 8}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {4, 8}, /* cost of loading MMX registers + in SImode and DImode */ + {4, 8}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {4, 8, 16}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {4, 8, 16}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 3, /* MMX or SSE register to integer */ + 0, /* size of prefetch block */ + 0, /* number of parallel prefetches */ }; +static const struct processor_costs i486_cost = { /* 486 specific costs */ 1, /* cost of an add instruction */ 1, /* cost of a lea instruction */ @@ -77,9 +130,36 @@ struct processor_costs i486_cost = { /* 486 specific 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 */ + 40, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ + 15, /* "large" insn */ + 3, /* MOVE_RATIO */ + 4, /* cost for loading QImode using movzbl */ + {2, 4, 2}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 4, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {8, 8, 8}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {8, 8, 8}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {4, 8}, /* cost of loading MMX registers + in SImode and DImode */ + {4, 8}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {4, 8, 16}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {4, 8, 16}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 3, /* MMX or SSE register to integer */ + 0, /* size of prefetch block */ + 0, /* number of parallel prefetches */ }; +static const struct processor_costs pentium_cost = { 1, /* cost of an add instruction */ 1, /* cost of a lea instruction */ @@ -87,35 +167,184 @@ struct processor_costs pentium_cost = { 1, /* constant shift costs */ 11, /* cost of starting a multiply */ 0, /* cost of multiply per each bit set */ - 25 /* cost of a divide/mod */ + 25, /* cost of a divide/mod */ + 3, /* cost of movsx */ + 2, /* cost of movzx */ + 8, /* "large" insn */ + 6, /* MOVE_RATIO */ + 6, /* cost for loading QImode using movzbl */ + {2, 4, 2}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 4, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {2, 2, 6}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ + 8, /* cost of moving MMX register */ + {8, 8}, /* cost of loading MMX registers + in SImode and DImode */ + {8, 8}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {4, 8, 16}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {4, 8, 16}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 3, /* MMX or SSE register to integer */ + 0, /* size of prefetch block */ + 0, /* number of parallel prefetches */ }; +static const struct processor_costs pentiumpro_cost = { 1, /* cost of an add instruction */ 1, /* cost of a lea instruction */ - 3, /* variable shift costs */ + 1, /* 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 */ + 17, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ + 8, /* "large" insn */ + 6, /* MOVE_RATIO */ + 2, /* cost for loading QImode using movzbl */ + {4, 4, 4}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 2, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {2, 2, 6}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {2, 2}, /* cost of loading MMX registers + in SImode and DImode */ + {2, 2}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {2, 2, 8}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {2, 2, 8}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 3, /* MMX or SSE register to integer */ + 32, /* size of prefetch block */ + 6, /* number of parallel prefetches */ }; -/* 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). */ - +static const struct processor_costs k6_cost = { 1, /* cost of an add instruction */ - 1, /* cost of a lea instruction */ + 2, /* 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 */ + 18, /* cost of a divide/mod */ + 2, /* cost of movsx */ + 2, /* cost of movzx */ + 8, /* "large" insn */ + 4, /* MOVE_RATIO */ + 3, /* cost for loading QImode using movzbl */ + {4, 5, 4}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 3, 2}, /* cost of storing integer registers */ + 4, /* cost of reg,reg fld/fst */ + {6, 6, 6}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {4, 4, 4}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {2, 2}, /* cost of loading MMX registers + in SImode and DImode */ + {2, 2}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {2, 2, 8}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {2, 2, 8}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 6, /* MMX or SSE register to integer */ + 32, /* size of prefetch block */ + 1, /* number of parallel prefetches */ +}; + +static const +struct processor_costs athlon_cost = { + 1, /* cost of an add instruction */ + 2, /* cost of a lea instruction */ + 1, /* variable shift costs */ + 1, /* constant shift costs */ + 5, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 42, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ + 8, /* "large" insn */ + 9, /* MOVE_RATIO */ + 4, /* cost for loading QImode using movzbl */ + {4, 5, 4}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 3, 2}, /* cost of storing integer registers */ + 4, /* cost of reg,reg fld/fst */ + {6, 6, 20}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {4, 4, 16}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {2, 2}, /* cost of loading MMX registers + in SImode and DImode */ + {2, 2}, /* cost of storing MMX registers + in SImode and DImode */ + 2, /* cost of moving SSE register */ + {2, 2, 8}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {2, 2, 8}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 6, /* MMX or SSE register to integer */ + 64, /* size of prefetch block */ + 6, /* number of parallel prefetches */ }; -struct processor_costs *ix86_cost = &pentium_cost; +static const +struct processor_costs pentium4_cost = { + 1, /* cost of an add instruction */ + 1, /* cost of a lea instruction */ + 8, /* variable shift costs */ + 8, /* constant shift costs */ + 30, /* cost of starting a multiply */ + 0, /* cost of multiply per each bit set */ + 112, /* cost of a divide/mod */ + 1, /* cost of movsx */ + 1, /* cost of movzx */ + 16, /* "large" insn */ + 6, /* MOVE_RATIO */ + 2, /* cost for loading QImode using movzbl */ + {4, 5, 4}, /* cost of loading integer registers + in QImode, HImode and SImode. + Relative to reg-reg move (2). */ + {2, 3, 2}, /* cost of storing integer registers */ + 2, /* cost of reg,reg fld/fst */ + {2, 2, 6}, /* cost of loading fp registers + in SFmode, DFmode and XFmode */ + {4, 4, 6}, /* cost of loading integer registers */ + 2, /* cost of moving MMX register */ + {2, 2}, /* cost of loading MMX registers + in SImode and DImode */ + {2, 2}, /* cost of storing MMX registers + in SImode and DImode */ + 12, /* cost of moving SSE register */ + {12, 12, 12}, /* cost of loading SSE registers + in SImode, DImode and TImode */ + {2, 2, 8}, /* cost of storing SSE registers + in SImode, DImode and TImode */ + 10, /* MMX or SSE register to integer */ + 64, /* size of prefetch block */ + 6, /* number of parallel prefetches */ +}; + +const struct processor_costs *ix86_cost = &pentium_cost; /* Processor feature/optimization bitmasks. */ #define m_386 (1<<PROCESSOR_I386) @@ -123,106 +352,475 @@ struct processor_costs *ix86_cost = &pentium_cost; #define m_PENT (1<<PROCESSOR_PENTIUM) #define m_PPRO (1<<PROCESSOR_PENTIUMPRO) #define m_K6 (1<<PROCESSOR_K6) +#define m_ATHLON (1<<PROCESSOR_ATHLON) +#define m_PENT4 (1<<PROCESSOR_PENTIUM4) -const int x86_use_leave = m_386 | m_K6; -const int x86_push_memory = m_386 | m_K6; +const int x86_use_leave = m_386 | m_K6 | m_ATHLON; +const int x86_push_memory = m_386 | m_K6 | m_ATHLON | m_PENT4; 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_movx = m_ATHLON | m_PPRO | m_PENT4 /* m_386 | m_K6 */; +const int x86_double_with_add = ~m_386; 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; +const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON | m_K6; +const int x86_cmove = m_PPRO | m_ATHLON | m_PENT4; +const int x86_3dnow_a = m_ATHLON; +const int x86_deep_branch = m_PPRO | m_K6 | m_ATHLON | m_PENT4; +const int x86_branch_hints = m_PENT4; +const int x86_use_sahf = m_PPRO | m_K6 | m_PENT4; +const int x86_partial_reg_stall = m_PPRO; +const int x86_use_loop = m_K6; +const int x86_use_fiop = ~(m_PPRO | m_ATHLON | m_PENT); +const int x86_use_mov0 = m_K6; +const int x86_use_cltd = ~(m_PENT | m_K6); +const int x86_read_modify_write = ~m_PENT; +const int x86_read_modify = ~(m_PENT | m_PPRO); +const int x86_split_long_moves = m_PPRO; +const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486; +const int x86_single_stringop = m_386 | m_PENT4; +const int x86_qimode_math = ~(0); +const int x86_promote_qi_regs = 0; +const int x86_himode_math = ~(m_PPRO); +const int x86_promote_hi_regs = m_PPRO; +const int x86_sub_esp_4 = m_ATHLON | m_PPRO | m_PENT4; +const int x86_sub_esp_8 = m_ATHLON | m_PPRO | m_386 | m_486 | m_PENT4; +const int x86_add_esp_4 = m_ATHLON | m_K6 | m_PENT4; +const int x86_add_esp_8 = m_ATHLON | m_PPRO | m_K6 | m_386 | m_486 | m_PENT4; +const int x86_integer_DFmode_moves = ~(m_ATHLON | m_PENT4); +const int x86_partial_reg_dependency = m_ATHLON | m_PENT4; +const int x86_memory_mismatch_stall = m_ATHLON | m_PENT4; +const int x86_accumulate_outgoing_args = m_ATHLON | m_PENT4 | m_PPRO; +const int x86_prologue_using_move = m_ATHLON | m_PENT4 | m_PPRO; +const int x86_epilogue_using_move = m_ATHLON | m_PENT4 | m_PPRO; +const int x86_decompose_lea = m_PENT4; + +/* In case the avreage insn count for single function invocation is + lower than this constant, emit fast (but longer) prologue and + epilogue code. */ +#define FAST_PROLOGUE_INSN_COUNT 30 +/* Set by prologue expander and used by epilogue expander to determine + the style used. */ +static int use_fast_prologue_epilogue; + +#define AT_BP(MODE) (gen_rtx_MEM ((MODE), hard_frame_pointer_rtx)) + +static const char *const hi_reg_name[] = HI_REGISTER_NAMES; /* names for 16 bit regs */ +static const char *const qi_reg_name[] = QI_REGISTER_NAMES; /* names for 8 bit regs (low) */ +static const char *const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; /* names for 8 bit regs (high) */ /* Array of the smallest class containing reg number REGNO, indexed by - REGNO. Used by REGNO_REG_CLASS in i386.h. */ + REGNO. Used by REGNO_REG_CLASS in i386.h. */ -enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] = +enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] = { /* ax, dx, cx, bx */ AREG, DREG, CREG, BREG, /* si, di, bp, sp */ - SIREG, DIREG, INDEX_REGS, GENERAL_REGS, + SIREG, DIREG, NON_Q_REGS, NON_Q_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 + NON_Q_REGS, + /* flags, fpsr, dirflag, frame */ + NO_REGS, NO_REGS, NO_REGS, NON_Q_REGS, + SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, + SSE_REGS, SSE_REGS, + MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, + MMX_REGS, MMX_REGS, + NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, + NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, + SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, + SSE_REGS, SSE_REGS, +}; + +/* The "default" register map used in 32bit mode. */ + +int const dbx_register_map[FIRST_PSEUDO_REGISTER] = +{ + 0, 2, 1, 3, 6, 7, 4, 5, /* general regs */ + 12, 13, 14, 15, 16, 17, 18, 19, /* fp regs */ + -1, -1, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ + 21, 22, 23, 24, 25, 26, 27, 28, /* SSE */ + 29, 30, 31, 32, 33, 34, 35, 36, /* MMX */ + -1, -1, -1, -1, -1, -1, -1, -1, /* extended integer registers */ + -1, -1, -1, -1, -1, -1, -1, -1, /* extended SSE registers */ +}; + +static int const x86_64_int_parameter_registers[6] = {5 /*RDI*/, 4 /*RSI*/, + 1 /*RDX*/, 2 /*RCX*/, + FIRST_REX_INT_REG /*R8 */, + FIRST_REX_INT_REG + 1 /*R9 */}; +static int const x86_64_int_return_registers[4] = {0 /*RAX*/, 1 /*RDI*/, 5, 4}; + +/* The "default" register map used in 64bit mode. */ +int const dbx64_register_map[FIRST_PSEUDO_REGISTER] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, /* general regs */ + 33, 34, 35, 36, 37, 38, 39, 40 /* fp regs */ + -1, -1, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ + 17, 18, 19, 20, 21, 22, 23, 24, /* SSE */ + 41, 42, 43, 44, 45, 46, 47, 48, /* MMX */ + 8,9,10,11,12,13,14,15, /* extended integer registers */ + 25, 26, 27, 28, 29, 30, 31, 32, /* extended SSE registers */ +}; + +/* 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 (gcc regno = 0) + 1 for %ecx (gcc regno = 2) + 2 for %edx (gcc regno = 1) + 3 for %ebx (gcc regno = 3) + 4 for %esp (gcc regno = 7) + 5 for %ebp (gcc regno = 6) + 6 for %esi (gcc regno = 4) + 7 for %edi (gcc 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 gcc equivalent) + 9 for %eflags (gcc regno = 17) + 10 for %trapno (no gcc 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) (gcc regno = 8) + 12 for %st(1) (gcc regno = 9) + 13 for %st(2) (gcc regno = 10) + 14 for %st(3) (gcc regno = 11) + 15 for %st(4) (gcc regno = 12) + 16 for %st(5) (gcc regno = 13) + 17 for %st(6) (gcc regno = 14) + 18 for %st(7) (gcc regno = 15) +*/ +int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] = +{ + 0, 2, 1, 3, 6, 7, 5, 4, /* general regs */ + 11, 12, 13, 14, 15, 16, 17, 18, /* fp regs */ + -1, 9, -1, -1, -1, /* arg, flags, fpsr, dir, frame */ + 21, 22, 23, 24, 25, 26, 27, 28, /* SSE registers */ + 29, 30, 31, 32, 33, 34, 35, 36, /* MMX registers */ + -1, -1, -1, -1, -1, -1, -1, -1, /* extemded integer registers */ + -1, -1, -1, -1, -1, -1, -1, -1, /* extemded SSE registers */ }; /* 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)(); +rtx ix86_compare_op0 = NULL_RTX; +rtx ix86_compare_op1 = NULL_RTX; + +#define MAX_386_STACK_LOCALS 3 +/* Size of the register save area. */ +#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16) + +/* Define the structure for the machine field in struct function. */ +struct machine_function +{ + rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; + int save_varrargs_registers; + int accesses_prev_frame; +}; + +#define ix86_stack_locals (cfun->machine->stack_locals) +#define ix86_save_varrargs_registers (cfun->machine->save_varrargs_registers) + +/* Structure describing stack frame layout. + Stack grows downward: + + [arguments] + <- ARG_POINTER + saved pc + + saved frame pointer if frame_pointer_needed + <- HARD_FRAME_POINTER + [saved regs] + + [padding1] \ + ) + [va_arg registers] ( + > to_allocate <- FRAME_POINTER + [frame] ( + ) + [padding2] / + */ +struct ix86_frame +{ + int nregs; + int padding1; + int va_arg_size; + HOST_WIDE_INT frame; + int padding2; + int outgoing_arguments_size; + int red_zone_size; + + HOST_WIDE_INT to_allocate; + /* The offsets relative to ARG_POINTER. */ + HOST_WIDE_INT frame_pointer_offset; + HOST_WIDE_INT hard_frame_pointer_offset; + HOST_WIDE_INT stack_pointer_offset; +}; + +/* Used to enable/disable debugging features. */ +const char *ix86_debug_arg_string, *ix86_debug_addr_string; +/* Code model option as passed by user. */ +const char *ix86_cmodel_string; +/* Parsed value. */ +enum cmodel ix86_cmodel; +/* Asm dialect. */ +const char *ix86_asm_string; +enum asm_dialect ix86_asm_dialect = ASM_ATT; /* which cpu are we scheduling for */ enum processor_type ix86_cpu; +/* which unit we are generating floating point math for */ +enum fpmath_unit ix86_fpmath; + /* 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> */ +const char *ix86_cpu_string; /* for -mcpu=<xxx> */ +const char *ix86_arch_string; /* for -march=<xxx> */ +const char *ix86_fpmath_string; /* for -mfpmath=<xxx> */ -/* Register allocation order */ -char *i386_reg_alloc_order; -static char regs_allocated[FIRST_PSEUDO_REGISTER]; +/* # of registers to use to pass arguments. */ +const char *ix86_regparm_string; -/* # of registers to use to pass arguments. */ -char *i386_regparm_string; +/* true if sse prefetch instruction is not NOOP. */ +int x86_prefetch_sse; -/* i386_regparm_string as a number */ -int i386_regparm; +/* ix86_regparm_string as a number */ +int ix86_regparm; /* Alignment to use for loops and jumps: */ -/* Power of two alignment for loops. */ -char *i386_align_loops_string; +/* Power of two alignment for loops. */ +const char *ix86_align_loops_string; -/* Power of two alignment for non-loop jumps. */ -char *i386_align_jumps_string; +/* Power of two alignment for non-loop jumps. */ +const char *ix86_align_jumps_string; /* Power of two alignment for stack boundary in bytes. */ -char *i386_preferred_stack_boundary_string; +const char *ix86_preferred_stack_boundary_string; /* Preferred alignment for stack boundary in bits. */ -int i386_preferred_stack_boundary; +int ix86_preferred_stack_boundary; /* Values 1-5: see jump.c */ -int i386_branch_cost; -char *i386_branch_cost_string; +int ix86_branch_cost; +const char *ix86_branch_cost_string; -/* Power of two alignment for functions. */ -int i386_align_funcs; -char *i386_align_funcs_string; +/* Power of two alignment for functions. */ +const char *ix86_align_funcs_string; -/* Power of two alignment for loops. */ -int i386_align_loops; +/* Prefix built by ASM_GENERATE_INTERNAL_LABEL. */ +static char internal_label_prefix[16]; +static int internal_label_prefix_len; + +static int local_symbolic_operand PARAMS ((rtx, enum machine_mode)); +static void output_pic_addr_const PARAMS ((FILE *, rtx, int)); +static void put_condition_code PARAMS ((enum rtx_code, enum machine_mode, + int, int, FILE *)); +static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx)); +static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code, + rtx *, rtx *)); +static rtx gen_push PARAMS ((rtx)); +static int memory_address_length PARAMS ((rtx addr)); +static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type)); +static int ix86_agi_dependant PARAMS ((rtx, rtx, enum attr_type)); +static int ix86_safe_length PARAMS ((rtx)); +static enum attr_memory ix86_safe_memory PARAMS ((rtx)); +static enum attr_pent_pair ix86_safe_pent_pair PARAMS ((rtx)); +static enum attr_ppro_uops ix86_safe_ppro_uops PARAMS ((rtx)); +static void ix86_dump_ppro_packet PARAMS ((FILE *)); +static void ix86_reorder_insn PARAMS ((rtx *, rtx *)); +static rtx * ix86_pent_find_pair PARAMS ((rtx *, rtx *, enum attr_pent_pair, + rtx)); +static void ix86_init_machine_status PARAMS ((struct function *)); +static void ix86_mark_machine_status PARAMS ((struct function *)); +static void ix86_free_machine_status PARAMS ((struct function *)); +static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode)); +static int ix86_safe_length_prefix PARAMS ((rtx)); +static int ix86_nsaved_regs PARAMS ((void)); +static void ix86_emit_save_regs PARAMS ((void)); +static void ix86_emit_save_regs_using_mov PARAMS ((rtx, HOST_WIDE_INT)); +static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int, int)); +static void ix86_set_move_mem_attrs_1 PARAMS ((rtx, rtx, rtx, rtx, rtx)); +static void ix86_sched_reorder_pentium PARAMS ((rtx *, rtx *)); +static void ix86_sched_reorder_ppro PARAMS ((rtx *, rtx *)); +static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void)); +static void ix86_adjust_counter PARAMS ((rtx, HOST_WIDE_INT)); +static rtx ix86_expand_aligntest PARAMS ((rtx, int)); +static void ix86_expand_strlensi_unroll_1 PARAMS ((rtx, rtx)); +static int ix86_issue_rate PARAMS ((void)); +static int ix86_adjust_cost PARAMS ((rtx, rtx, rtx, int)); +static void ix86_sched_init PARAMS ((FILE *, int, int)); +static int ix86_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int)); +static int ix86_variable_issue PARAMS ((FILE *, int, rtx, int)); +static void ix86_init_mmx_sse_builtins PARAMS ((void)); + +struct ix86_address +{ + rtx base, index, disp; + HOST_WIDE_INT scale; +}; -/* Power of two alignment for non-loop jumps. */ -int i386_align_jumps; +static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *)); + +struct builtin_description; +static rtx ix86_expand_sse_comi PARAMS ((const struct builtin_description *, + tree, rtx)); +static rtx ix86_expand_sse_compare PARAMS ((const struct builtin_description *, + tree, rtx)); +static rtx ix86_expand_unop1_builtin PARAMS ((enum insn_code, tree, rtx)); +static rtx ix86_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx, int)); +static rtx ix86_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx)); +static rtx ix86_expand_timode_binop_builtin PARAMS ((enum insn_code, + tree, rtx)); +static rtx ix86_expand_store_builtin PARAMS ((enum insn_code, tree)); +static rtx safe_vector_operand PARAMS ((rtx, enum machine_mode)); +static enum rtx_code ix86_fp_compare_code_to_integer PARAMS ((enum rtx_code)); +static void ix86_fp_comparison_codes PARAMS ((enum rtx_code code, + enum rtx_code *, + enum rtx_code *, + enum rtx_code *)); +static rtx ix86_expand_fp_compare PARAMS ((enum rtx_code, rtx, rtx, rtx, + rtx *, rtx *)); +static int ix86_fp_comparison_arithmetics_cost PARAMS ((enum rtx_code code)); +static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code)); +static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code)); +static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code)); +static int ix86_save_reg PARAMS ((int, int)); +static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *)); +static int ix86_comp_type_attributes PARAMS ((tree, tree)); +const struct attribute_spec ix86_attribute_table[]; +static tree ix86_handle_cdecl_attribute PARAMS ((tree *, tree, tree, int, bool *)); +static tree ix86_handle_regparm_attribute PARAMS ((tree *, tree, tree, int, bool *)); + +#ifdef DO_GLOBAL_CTORS_BODY +static void ix86_svr3_asm_out_constructor PARAMS ((rtx, int)); +#endif +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). + */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_MEMORY_CLASS + }; +static const char * const x86_64_reg_class_name[] = + {"no", "integer", "integerSI", "sse", "sseSF", "sseDF", "sseup", "x87", "x87up", "no"}; + +#define MAX_CLASSES 4 +static int classify_argument PARAMS ((enum machine_mode, tree, + enum x86_64_reg_class [MAX_CLASSES], + int)); +static int examine_argument PARAMS ((enum machine_mode, tree, int, int *, + int *)); +static rtx construct_container PARAMS ((enum machine_mode, tree, int, int, int, + const int *, int)); +static enum x86_64_reg_class merge_classes PARAMS ((enum x86_64_reg_class, + enum x86_64_reg_class)); + +/* Initialize the GCC target structure. */ +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table +#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES +# undef TARGET_MERGE_DECL_ATTRIBUTES +# define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes +#endif + +#undef TARGET_COMP_TYPE_ATTRIBUTES +#define TARGET_COMP_TYPE_ATTRIBUTES ix86_comp_type_attributes + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS ix86_init_builtins + +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN ix86_expand_builtin + +#if defined (OSF_OS) || defined (TARGET_OSF1ELF) + static void ix86_osf_output_function_prologue PARAMS ((FILE *, + HOST_WIDE_INT)); +# undef TARGET_ASM_FUNCTION_PROLOGUE +# define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_function_prologue +#endif + +#undef TARGET_ASM_OPEN_PAREN +#define TARGET_ASM_OPEN_PAREN "" +#undef TARGET_ASM_CLOSE_PAREN +#define TARGET_ASM_CLOSE_PAREN "" + +#undef TARGET_ASM_ALIGNED_HI_OP +#define TARGET_ASM_ALIGNED_HI_OP ASM_SHORT +#undef TARGET_ASM_ALIGNED_SI_OP +#define TARGET_ASM_ALIGNED_SI_OP ASM_LONG +#ifdef ASM_QUAD +#undef TARGET_ASM_ALIGNED_DI_OP +#define TARGET_ASM_ALIGNED_DI_OP ASM_QUAD +#endif + +#undef TARGET_ASM_UNALIGNED_HI_OP +#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP +#undef TARGET_ASM_UNALIGNED_SI_OP +#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP +#undef TARGET_ASM_UNALIGNED_DI_OP +#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP + +#undef TARGET_SCHED_ADJUST_COST +#define TARGET_SCHED_ADJUST_COST ix86_adjust_cost +#undef TARGET_SCHED_ISSUE_RATE +#define TARGET_SCHED_ISSUE_RATE ix86_issue_rate +#undef TARGET_SCHED_VARIABLE_ISSUE +#define TARGET_SCHED_VARIABLE_ISSUE ix86_variable_issue +#undef TARGET_SCHED_INIT +#define TARGET_SCHED_INIT ix86_sched_init +#undef TARGET_SCHED_REORDER +#define TARGET_SCHED_REORDER ix86_sched_reorder + +struct gcc_target targetm = TARGET_INITIALIZER; + /* 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 @@ -235,238 +833,367 @@ int i386_align_jumps; void override_options () { - int ch, i, j; - int def_align; + int i; + /* Comes from final.c -- no real reason to change it. */ +#define MAX_CODE_ALIGN 16 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} + const struct processor_costs *cost; /* Processor costs */ + const int target_enable; /* Target flags to enable. */ + const int target_disable; /* Target flags to disable. */ + const int align_loop; /* Default alignments. */ + const int align_loop_max_skip; + const int align_jump; + const int align_jump_max_skip; + const int align_func; + const int branch_cost; + } + const processor_target_table[PROCESSOR_max] = + { + {&i386_cost, 0, 0, 4, 3, 4, 3, 4, 1}, + {&i486_cost, 0, 0, 16, 15, 16, 15, 16, 1}, + {&pentium_cost, 0, 0, 16, 7, 16, 7, 16, 1}, + {&pentiumpro_cost, 0, 0, 16, 15, 16, 7, 16, 1}, + {&k6_cost, 0, 0, 32, 7, 32, 7, 32, 1}, + {&athlon_cost, 0, 0, 16, 7, 64, 7, 16, 1}, + {&pentium4_cost, 0, 0, 0, 0, 0, 0, 0, 1} }; - 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) + static const char * const cpu_names[] = TARGET_CPU_DEFAULT_NAMES; + static struct pta { - for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + const char *const name; /* processor name or nickname. */ + const enum processor_type processor; + const enum pta_flags { - int regno = 0; + PTA_SSE = 1, + PTA_SSE2 = 2, + PTA_MMX = 4, + PTA_PREFETCH_SSE = 8, + PTA_3DNOW = 16, + PTA_3DNOW_A = 64 + } flags; + } + const processor_alias_table[] = + { + {"i386", PROCESSOR_I386, 0}, + {"i486", PROCESSOR_I486, 0}, + {"i586", PROCESSOR_PENTIUM, 0}, + {"pentium", PROCESSOR_PENTIUM, 0}, + {"pentium-mmx", PROCESSOR_PENTIUM, PTA_MMX}, + {"i686", PROCESSOR_PENTIUMPRO, 0}, + {"pentiumpro", PROCESSOR_PENTIUMPRO, 0}, + {"pentium2", PROCESSOR_PENTIUMPRO, PTA_MMX}, + {"pentium3", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE}, + {"pentium4", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2 | + PTA_MMX | PTA_PREFETCH_SSE}, + {"k6", PROCESSOR_K6, PTA_MMX}, + {"k6-2", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, + {"k6-3", PROCESSOR_K6, PTA_MMX | PTA_3DNOW}, + {"athlon", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW + | PTA_3DNOW_A}, + {"athlon-tbird", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE + | PTA_3DNOW | PTA_3DNOW_A}, + {"athlon-4", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW + | PTA_3DNOW_A | PTA_SSE}, + {"athlon-xp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW + | PTA_3DNOW_A | PTA_SSE}, + {"athlon-mp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW + | PTA_3DNOW_A | PTA_SSE}, + }; - 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); - } + int const pta_size = sizeof (processor_alias_table) / sizeof (struct pta); - if (regs_allocated[regno]) - fatal ("Register '%c' already specified in allocation order", ch); +#ifdef SUBTARGET_OVERRIDE_OPTIONS + SUBTARGET_OVERRIDE_OPTIONS; +#endif - regs_allocated[regno] = 1; - } + if (!ix86_cpu_string && ix86_arch_string) + ix86_cpu_string = ix86_arch_string; + if (!ix86_cpu_string) + ix86_cpu_string = cpu_names [TARGET_CPU_DEFAULT]; + if (!ix86_arch_string) + ix86_arch_string = TARGET_64BIT ? "athlon-4" : "i386"; + + if (ix86_cmodel_string != 0) + { + if (!strcmp (ix86_cmodel_string, "small")) + ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; + else if (flag_pic) + sorry ("code model %s not supported in PIC mode", ix86_cmodel_string); + else if (!strcmp (ix86_cmodel_string, "32")) + ix86_cmodel = CM_32; + else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic) + ix86_cmodel = CM_KERNEL; + else if (!strcmp (ix86_cmodel_string, "medium") && !flag_pic) + ix86_cmodel = CM_MEDIUM; + else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic) + ix86_cmodel = CM_LARGE; + else + error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string); } - - if (ix86_arch_string == 0) + else { - ix86_arch_string = PROCESSOR_PENTIUM_STRING; - if (ix86_cpu_string == 0) - ix86_cpu_string = PROCESSOR_DEFAULT_STRING; + ix86_cmodel = CM_32; + if (TARGET_64BIT) + ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; } - - for (i = 0; i < ptt_size; i++) - if (! strcmp (ix86_arch_string, processor_target_table[i].name)) + if (ix86_asm_string != 0) + { + if (!strcmp (ix86_asm_string, "intel")) + ix86_asm_dialect = ASM_INTEL; + else if (!strcmp (ix86_asm_string, "att")) + ix86_asm_dialect = ASM_ATT; + else + error ("bad value (%s) for -masm= switch", ix86_asm_string); + } + if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32)) + error ("code model `%s' not supported in the %s bit mode", + ix86_cmodel_string, TARGET_64BIT ? "64" : "32"); + if (ix86_cmodel == CM_LARGE) + sorry ("code model `large' not supported yet"); + if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0)) + sorry ("%i-bit mode not compiled in", + (target_flags & MASK_64BIT) ? 64 : 32); + + for (i = 0; i < pta_size; i++) + if (! strcmp (ix86_arch_string, processor_alias_table[i].name)) { - ix86_arch = processor_target_table[i].processor; - if (ix86_cpu_string == 0) - ix86_cpu_string = processor_target_table[i].name; + ix86_arch = processor_alias_table[i].processor; + /* Default cpu tuning to the architecture. */ + ix86_cpu = ix86_arch; + if (processor_alias_table[i].flags & PTA_MMX + && !(target_flags & MASK_MMX_SET)) + target_flags |= MASK_MMX; + if (processor_alias_table[i].flags & PTA_3DNOW + && !(target_flags & MASK_3DNOW_SET)) + target_flags |= MASK_3DNOW; + if (processor_alias_table[i].flags & PTA_3DNOW_A + && !(target_flags & MASK_3DNOW_A_SET)) + target_flags |= MASK_3DNOW_A; + if (processor_alias_table[i].flags & PTA_SSE + && !(target_flags & MASK_SSE_SET)) + target_flags |= MASK_SSE; + if (processor_alias_table[i].flags & PTA_SSE2 + && !(target_flags & MASK_SSE2_SET)) + target_flags |= MASK_SSE2; + if (processor_alias_table[i].flags & PTA_PREFETCH_SSE) + x86_prefetch_sse = true; 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 (i == pta_size) + error ("bad value (%s) for -march= switch", ix86_arch_string); - 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)) + for (i = 0; i < pta_size; i++) + if (! strcmp (ix86_cpu_string, processor_alias_table[i].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; + ix86_cpu = processor_alias_table[i].processor; break; } + if (processor_alias_table[i].flags & PTA_PREFETCH_SSE) + x86_prefetch_sse = true; + if (i == pta_size) + error ("bad value (%s) for -mcpu= switch", ix86_cpu_string); + + if (optimize_size) + ix86_cost = &size_cost; + else + ix86_cost = processor_target_table[ix86_cpu].cost; + target_flags |= processor_target_table[ix86_cpu].target_enable; + target_flags &= ~processor_target_table[ix86_cpu].target_disable; + + /* Arrange to set up i386_stack_locals for all functions. */ + init_machine_status = ix86_init_machine_status; + mark_machine_status = ix86_mark_machine_status; + free_machine_status = ix86_free_machine_status; - if (j == ptt_size) + /* Validate -mregparm= value. */ + if (ix86_regparm_string) { - error ("bad value (%s) for -mcpu= switch", ix86_cpu_string); - ix86_cpu_string = PROCESSOR_DEFAULT_STRING; - ix86_cpu = PROCESSOR_DEFAULT; + i = atoi (ix86_regparm_string); + if (i < 0 || i > REGPARM_MAX) + error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX); + else + ix86_regparm = i; } + else + if (TARGET_64BIT) + ix86_regparm = REGPARM_MAX; - /* Validate -mregparm= value. */ - if (i386_regparm_string) + /* If the user has provided any of the -malign-* options, + warn and use that value only if -falign-* is not set. + Remove this code in GCC 3.2 or later. */ + if (ix86_align_loops_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); + warning ("-malign-loops is obsolete, use -falign-loops"); + if (align_loops == 0) + { + i = atoi (ix86_align_loops_string); + if (i < 0 || i > MAX_CODE_ALIGN) + error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); + else + align_loops = 1 << i; + } } - /* 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) + if (ix86_align_jumps_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); + warning ("-malign-jumps is obsolete, use -falign-jumps"); + if (align_jumps == 0) + { + i = atoi (ix86_align_jumps_string); + if (i < 0 || i > MAX_CODE_ALIGN) + error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); + else + align_jumps = 1 << i; + } } - /* 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) + if (ix86_align_funcs_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); + warning ("-malign-functions is obsolete, use -falign-functions"); + if (align_functions == 0) + { + i = atoi (ix86_align_funcs_string); + if (i < 0 || i > MAX_CODE_ALIGN) + error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN); + else + align_functions = 1 << i; + } } - /* Validate -malign-functions= value, or provide default. */ - i386_align_funcs = def_align; - if (i386_align_funcs_string) + /* Default align_* from the processor table. */ + if (align_loops == 0) { - 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); + align_loops = processor_target_table[ix86_cpu].align_loop; + align_loops_max_skip = processor_target_table[ix86_cpu].align_loop_max_skip; + } + if (align_jumps == 0) + { + align_jumps = processor_target_table[ix86_cpu].align_jump; + align_jumps_max_skip = processor_target_table[ix86_cpu].align_jump_max_skip; + } + if (align_functions == 0) + { + align_functions = processor_target_table[ix86_cpu].align_func; } - /* 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) + /* Validate -mpreferred-stack-boundary= value, or provide default. + The default of 128 bits is for Pentium III's SSE __m128, but we + don't want additional code to keep the stack aligned when + optimizing for code size. */ + ix86_preferred_stack_boundary = (optimize_size + ? TARGET_64BIT ? 64 : 32 + : 128); + if (ix86_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; + i = atoi (ix86_preferred_stack_boundary_string); + if (i < (TARGET_64BIT ? 3 : 2) || i > 12) + error ("-mpreferred-stack-boundary=%d is not between %d and 12", i, + TARGET_64BIT ? 3 : 2); + else + ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; } - /* Validate -mbranch-cost= value, or provide default. */ - i386_branch_cost = 1; - if (i386_branch_cost_string) + /* Validate -mbranch-cost= value, or provide default. */ + ix86_branch_cost = processor_target_table[ix86_cpu].branch_cost; + if (ix86_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); + i = atoi (ix86_branch_cost_string); + if (i < 0 || i > 5) + error ("-mbranch-cost=%d is not between 0 and 5", i); + else + ix86_branch_cost = i; } /* 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; + /* If we're doing fast math, we don't care about comparison order + wrt NaNs. This lets us use a shorter comparison sequence. */ + if (flag_unsafe_math_optimizations) + target_flags &= ~MASK_IEEE_FP; - /* User specified the register allocation order. */ + if (TARGET_64BIT) + { + if (TARGET_ALIGN_DOUBLE) + error ("-malign-double makes no sense in the 64bit mode"); + if (TARGET_RTD) + error ("-mrtd calling convention not supported in the 64bit mode"); + /* Enable by default the SSE and MMX builtins. */ + target_flags |= (MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE); + ix86_fpmath = FPMATH_SSE; + } + else + ix86_fpmath = FPMATH_387; - if (i386_reg_alloc_order) + if (ix86_fpmath_string != 0) { - for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++) + if (! strcmp (ix86_fpmath_string, "387")) + ix86_fpmath = FPMATH_387; + else if (! strcmp (ix86_fpmath_string, "sse")) { - int regno = 0; - - switch (ch) + if (!TARGET_SSE) { - 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; + warning ("SSE instruction set disabled, using 387 arithmetics"); + ix86_fpmath = FPMATH_387; } - - reg_alloc_order[order++] = regno; + else + ix86_fpmath = FPMATH_SSE; } - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + else if (! strcmp (ix86_fpmath_string, "387,sse") + || ! strcmp (ix86_fpmath_string, "sse,387")) { - if (! regs_allocated[i]) - reg_alloc_order[order++] = i; + if (!TARGET_SSE) + { + warning ("SSE instruction set disabled, using 387 arithmetics"); + ix86_fpmath = FPMATH_387; + } + else if (!TARGET_80387) + { + warning ("387 instruction set disabled, using SSE arithmetics"); + ix86_fpmath = FPMATH_SSE; + } + else + ix86_fpmath = FPMATH_SSE | FPMATH_387; } + else + error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string); } - /* If user did not specify a register allocation order, use natural order. */ - else + /* It makes no sense to ask for just SSE builtins, so MMX is also turned + on by -msse. */ + if (TARGET_SSE) + { + target_flags |= MASK_MMX; + x86_prefetch_sse = true; + } + + /* If it has 3DNow! it also has MMX so MMX is also turned on by -m3dnow */ + if (TARGET_3DNOW) { - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - reg_alloc_order[i] = i; + target_flags |= MASK_MMX; + /* If we are targetting the Athlon architecture, enable the 3Dnow/MMX + extensions it adds. */ + if (x86_3dnow_a & (1 << ix86_arch)) + target_flags |= MASK_3DNOW_A; } + if ((x86_accumulate_outgoing_args & CPUMASK) + && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS_SET) + && !optimize_size) + target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; + + /* Figure out what ASM_GENERATE_INTERNAL_LABEL builds as a prefix. */ + { + char *p; + ASM_GENERATE_INTERNAL_LABEL (internal_label_prefix, "LX", 0); + p = strchr (internal_label_prefix, 'X'); + internal_label_prefix_len = p - internal_label_prefix; + *p = '\0'; + } } void @@ -480,170 +1207,215 @@ optimization_options (level, size) 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) + if (TARGET_64BIT && optimize >= 1) + flag_omit_frame_pointer = 1; + if (TARGET_64BIT) { - 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); + flag_pcc_struct_return = 0; + flag_asynchronous_unwind_tables = 1; } - return op; } -/* Return nonzero if the rtx is aligned */ - -static int -i386_aligned_reg_p (regno) - int regno; +/* Table of valid machine attributes. */ +const struct attribute_spec ix86_attribute_table[] = { - return (regno == STACK_POINTER_REGNUM - || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM)); -} + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + /* Stdcall attribute says callee is responsible for popping arguments + if they are not variable. */ + { "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, + /* Cdecl attribute says the callee is a normal C declaration */ + { "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute }, + /* Regparm attribute specifies how many integer arguments are to be + passed in registers. */ + { "regparm", 1, 1, false, true, true, ix86_handle_regparm_attribute }, +#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES + { "dllimport", 0, 0, false, false, false, ix86_handle_dll_attribute }, + { "dllexport", 0, 0, false, false, false, ix86_handle_dll_attribute }, + { "shared", 0, 0, true, false, false, ix86_handle_shared_attribute }, +#endif + { NULL, 0, 0, false, false, false, NULL } +}; -int -i386_aligned_p (op) - rtx op; +/* Handle a "cdecl" or "stdcall" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; { - /* Registers and immediate operands are always "aligned". */ - if (GET_CODE (op) != MEM) - return 1; + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - /* Don't even try to do any aligned optimizations with volatiles. */ - if (MEM_VOLATILE_P (op)) - return 0; + if (TARGET_64BIT) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } - /* Get address of memory operand. */ - op = XEXP (op, 0); + return NULL_TREE; +} - switch (GET_CODE (op)) +/* Handle a "regparm" attribute; + arguments as in struct attribute_spec.handler. */ +static tree +ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) { - case CONST_INT: - if (INTVAL (op) & 3) - break; - return 1; + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else + { + tree cst; - /* Match "reg + offset" */ - case PLUS: - if (GET_CODE (XEXP (op, 1)) != CONST_INT) - break; - if (INTVAL (XEXP (op, 1)) & 3) - break; + cst = TREE_VALUE (args); + if (TREE_CODE (cst) != INTEGER_CST) + { + warning ("`%s' attribute requires an integer constant argument", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if (compare_tree_int (cst, REGPARM_MAX) > 0) + { + warning ("argument to `%s' attribute larger than %d", + IDENTIFIER_POINTER (name), REGPARM_MAX); + *no_add_attrs = true; + } + } - op = XEXP (op, 0); - if (GET_CODE (op) != REG) - break; + return NULL_TREE; +} - /* ... fall through ... */ +#if defined (OSF_OS) || defined (TARGET_OSF1ELF) - case REG: - return i386_aligned_reg_p (REGNO (op)); +/* Generate 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. - default: - break; - } + Refer to the array `regs_ever_live' to determine which registers to + save; `regs_ever_live[I]' is nonzero if register number I is ever + used in the function. This function is responsible for knowing + which registers should not be saved even if used. - 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. */ + 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). */ -int -i386_cc_probably_useless_p (insn) - rtx insn; +static void +ix86_osf_output_function_prologue (file, size) + FILE *file; + HOST_WIDE_INT size; { - 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. */ + const char *prefix = ""; + const char *const lprefix = LPREFIX; + int labelno = profile_label_no; -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; -} +#ifdef OSF_OS -/* 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. */ + if (TARGET_UNDERSCORES) + prefix = "_"; -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; + if (current_function_profile && 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); + } - /* Stdcall attribute says callee is responsible for popping arguments - if they are not variable. */ - if (is_attribute_p ("stdcall", identifier)) - return (args == NULL_TREE); + else if (HALF_PIC_P ()) + { + rtx symref; - /* Cdecl attribute says the callee is a normal C declaration. */ - if (is_attribute_p ("cdecl", identifier)) - return (args == NULL_TREE); + HALF_PIC_EXTERNAL ("_mcount_ptr"); + symref = HALF_PIC_PTR (gen_rtx_SYMBOL_REF (Pmode, + "_mcount_ptr")); - /* Regparm attribute specifies how many integer arguments are to be - passed in registers. */ - if (is_attribute_p ("regparm", identifier)) - { - tree cst; + 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"); + } - if (! args || TREE_CODE (args) != TREE_LIST - || TREE_CHAIN (args) != NULL_TREE - || TREE_VALUE (args) == NULL_TREE) - return 0; + 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"); + } + } - cst = TREE_VALUE (args); - if (TREE_CODE (cst) != INTEGER_CST) - return 0; +#else /* !OSF_OS */ - if (TREE_INT_CST_HIGH (cst) != 0 - || TREE_INT_CST_LOW (cst) < 0 - || TREE_INT_CST_LOW (cst) > REGPARM_MAX) - return 0; + if (current_function_profile && OSF_PROFILE_BEFORE_PROLOGUE) + { + if (!flag_pic) + { + fprintf (file, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); + fprintf (file, "\tcall *%s_mcount_ptr\n", prefix); + } - return 1; + 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"); + } } +#endif /* !OSF_OS */ - return 0; + function_prologue (file, size); } +#endif /* OSF_OS || TARGET_OSF1ELF */ + /* 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) +static int +ix86_comp_type_attributes (type1, type2) tree type1; tree type2; { - /* Check for mismatch of non-default calling convention. */ - char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; + /* Check for mismatch of non-default calling convention. */ + const char *const rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; if (TREE_CODE (type1) != FUNCTION_TYPE) return 1; @@ -654,7 +1426,6 @@ i386_comp_type_attributes (type1, type2) return 0; return 1; } - /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. @@ -674,17 +1445,17 @@ i386_comp_type_attributes (type1, type2) The attribute stdcall is equivalent to RTD on a per module basis. */ int -i386_return_pops_args (fundecl, funtype, size) +ix86_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. */ + /* 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. */ + /* Stdcall functions will pop the stack if not variable args. */ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) rtd = 1; @@ -696,15 +1467,35 @@ i386_return_pops_args (fundecl, funtype, size) } /* Lose any fake structure return argument. */ - if (aggregate_value_p (TREE_TYPE (funtype))) + if (aggregate_value_p (TREE_TYPE (funtype)) + && !TARGET_64BIT) return GET_MODE_SIZE (Pmode); return 0; } - /* Argument support functions. */ +/* Return true when register may be used to pass function parameters. */ +bool +ix86_function_arg_regno_p (regno) + int regno; +{ + int i; + if (!TARGET_64BIT) + return (regno < REGPARM_MAX + || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno])); + if (SSE_REGNO_P (regno) && TARGET_SSE) + return true; + /* RAX is used as hidden argument to va_arg functions. */ + if (!regno) + return true; + for (i = 0; i < REGPARM_MAX; i++) + if (regno == x86_64_int_parameter_registers[i]) + return true; + return false; +} + /* 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. */ @@ -735,14 +1526,16 @@ init_cumulative_args (cum, fntype, libname) *cum = zero_cum; /* Set up the number of registers to use for passing arguments. */ - cum->nregs = i386_regparm; - if (fntype) + cum->nregs = ix86_regparm; + cum->sse_nregs = SSE_REGPARM_MAX; + if (fntype && !TARGET_64BIT) { tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); if (attr) cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); } + cum->maybe_vaarg = false; /* Determine if this function has variable arguments. This is indicated by the last argument being 'void_type_mode' if there @@ -756,9 +1549,16 @@ init_cumulative_args (cum, fntype, libname) { next_param = TREE_CHAIN (param); if (next_param == 0 && TREE_VALUE (param) != void_type_node) - cum->nregs = 0; + { + if (!TARGET_64BIT) + cum->nregs = 0; + cum->maybe_vaarg = true; + } } } + if ((!fntype && !libname) + || (fntype && !TYPE_ARG_TYPES (fntype))) + cum->maybe_vaarg = 1; if (TARGET_DEBUG_ARG) fprintf (stderr, ", nregs=%d )\n", cum->nregs); @@ -766,6 +1566,445 @@ init_cumulative_args (cum, fntype, libname) return; } +/* x86-64 register passing impleemntation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (class1, class2) + enum x86_64_reg_class class1, class2; +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS + || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + BIT_OFFSET is used internally for handling records and specifies offset + of the offset in bits modulo 256 to avoid overflow cases. + + See the x86-64 PS ABI for details. +*/ + +static int +classify_argument (mode, type, classes, bit_offset) + enum machine_mode mode; + tree type; + enum x86_64_reg_class classes[MAX_CLASSES]; + int bit_offset; +{ + int bytes = + (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); + int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + if (type && AGGREGATE_TYPE_P (type)) + { + int i; + tree field; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* On x86-64 we pass structures larger than 16 bytes on the stack. */ + if (bytes > 16) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Zero sized arrays or structures are NO_CLASS. We return 0 to + signalize memory class, so handle it as special case. */ + if (!words) + { + classes[0] = X86_64_NO_CLASS; + return 1; + } + + /* Classify each field of record and merge classes. */ + if (TREE_CODE (type) == RECORD_TYPE) + { + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL) + { + int num; + + /* Bitfields are always classified as integer. Handle them + early, since later code would consider them to be + misaligned integers. */ + if (DECL_BIT_FIELD (field)) + { + for (i = int_bit_position (field) / 8 / 8; + i < (int_bit_position (field) + + tree_low_cst (DECL_SIZE (field), 0) + + 63) / 8 / 8; i++) + classes[i] = + merge_classes (X86_64_INTEGER_CLASS, + classes[i]); + } + else + { + num = classify_argument (TYPE_MODE (TREE_TYPE (field)), + TREE_TYPE (field), subclasses, + (int_bit_position (field) + + bit_offset) % 256); + if (!num) + return 0; + for (i = 0; i < num; i++) + { + int pos = + (int_bit_position (field) + bit_offset) / 8 / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + } + } + } + } + /* Arrays are handled as small records. */ + else if (TREE_CODE (type) == ARRAY_TYPE) + { + int num; + num = classify_argument (TYPE_MODE (TREE_TYPE (type)), + TREE_TYPE (type), subclasses, bit_offset); + if (!num) + return 0; + + /* The partial classes are now full classes. */ + if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4) + subclasses[0] = X86_64_SSE_CLASS; + if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4) + subclasses[0] = X86_64_INTEGER_CLASS; + + for (i = 0; i < words; i++) + classes[i] = subclasses[i % num]; + } + /* Unions are similar to RECORD_TYPE but offset is always 0. */ + else if (TREE_CODE (type) == UNION_TYPE) + { + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL) + { + int num; + num = classify_argument (TYPE_MODE (TREE_TYPE (field)), + TREE_TYPE (field), subclasses, + bit_offset); + if (!num) + return 0; + for (i = 0; i < num; i++) + classes[i] = merge_classes (subclasses[i], classes[i]); + } + } + } + else + abort (); + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if (classes[i] == X86_64_X87UP_CLASS + && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + /* Compute alignment needed. We align all types to natural boundaries with + exception of XFmode that is aligned to 64bits. */ + if (mode != VOIDmode && mode != BLKmode) + { + int mode_alignment = GET_MODE_BITSIZE (mode); + + if (mode == XFmode) + mode_alignment = 128; + else if (mode == XCmode) + mode_alignment = 256; + /* Misaligned fields are always returned in memory. */ + if (bit_offset % mode_alignment) + return 0; + } + + /* Classification of atomic types. */ + switch (mode) + { + case DImode: + case SImode: + case HImode: + case QImode: + case CSImode: + case CHImode: + case CQImode: + if (bit_offset + GET_MODE_BITSIZE (mode) <= 32) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + return 1; + case CDImode: + case TImode: + classes[0] = classes[1] = X86_64_INTEGER_CLASS; + return 2; + case CTImode: + classes[0] = classes[1] = X86_64_INTEGER_CLASS; + classes[2] = classes[3] = X86_64_INTEGER_CLASS; + return 4; + case SFmode: + if (!(bit_offset % 64)) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case DFmode: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case TFmode: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case TCmode: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + classes[2] = X86_64_X87_CLASS; + classes[3] = X86_64_X87UP_CLASS; + return 4; + case DCmode: + classes[0] = X86_64_SSEDF_CLASS; + classes[1] = X86_64_SSEDF_CLASS; + return 2; + case SCmode: + classes[0] = X86_64_SSE_CLASS; + return 1; + case BLKmode: + return 0; + default: + abort (); + } +} + +/* Examine the argument and return set number of register required in each + class. Return 0 iff parameter should be passed in memory. */ +static int +examine_argument (mode, type, in_return, int_nregs, sse_nregs) + enum machine_mode mode; + tree type; + int *int_nregs, *sse_nregs; + int in_return; +{ + enum x86_64_reg_class class[MAX_CLASSES]; + int n = classify_argument (mode, type, class, 0); + + *int_nregs = 0; + *sse_nregs = 0; + if (!n) + return 0; + for (n--; n >= 0; n--) + switch (class[n]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + (*int_nregs)++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + (*sse_nregs)++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + if (!in_return) + return 0; + break; + case X86_64_MEMORY_CLASS: + abort (); + } + return 1; +} +/* Construct container for the argument used by GCC interface. See + FUNCTION_ARG for the detailed description. */ +static rtx +construct_container (mode, type, in_return, nintregs, nsseregs, intreg, sse_regno) + enum machine_mode mode; + tree type; + int in_return; + int nintregs, nsseregs; + const int * intreg; + int sse_regno; +{ + enum machine_mode tmpmode; + int bytes = + (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); + enum x86_64_reg_class class[MAX_CLASSES]; + int n; + int i; + int nexps = 0; + int needed_sseregs, needed_intregs; + rtx exp[MAX_CLASSES]; + rtx ret; + + n = classify_argument (mode, type, class, 0); + if (TARGET_DEBUG_ARG) + { + if (!n) + fprintf (stderr, "Memory class\n"); + else + { + fprintf (stderr, "Classes:"); + for (i = 0; i < n; i++) + { + fprintf (stderr, " %s", x86_64_reg_class_name[class[i]]); + } + fprintf (stderr, "\n"); + } + } + if (!n) + return NULL; + if (!examine_argument (mode, type, in_return, &needed_intregs, &needed_sseregs)) + return NULL; + if (needed_intregs > nintregs || needed_sseregs > nsseregs) + return NULL; + + /* First construct simple cases. Avoid SCmode, since we want to use + single register to pass this type. */ + if (n == 1 && mode != SCmode) + switch (class[0]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + return gen_rtx_REG (mode, intreg[0]); + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + return gen_rtx_REG (mode, SSE_REGNO (sse_regno)); + case X86_64_X87_CLASS: + return gen_rtx_REG (mode, FIRST_STACK_REG); + case X86_64_NO_CLASS: + /* Zero sized array, struct or class. */ + return NULL; + default: + abort (); + } + if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS) + return gen_rtx_REG (TImode, SSE_REGNO (sse_regno)); + if (n == 2 + && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS) + return gen_rtx_REG (TFmode, FIRST_STACK_REG); + if (n == 2 && class[0] == X86_64_INTEGER_CLASS + && class[1] == X86_64_INTEGER_CLASS + && (mode == CDImode || mode == TImode) + && intreg[0] + 1 == intreg[1]) + return gen_rtx_REG (mode, intreg[0]); + if (n == 4 + && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS + && class[2] == X86_64_X87_CLASS && class[3] == X86_64_X87UP_CLASS) + return gen_rtx_REG (TCmode, FIRST_STACK_REG); + + /* Otherwise figure out the entries of the PARALLEL. */ + for (i = 0; i < n; i++) + { + switch (class[i]) + { + case X86_64_NO_CLASS: + break; + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + /* Merge TImodes on aligned occassions here too. */ + if (i * 8 + 8 > bytes) + tmpmode = mode_for_size ((bytes - i * 8) * BITS_PER_UNIT, MODE_INT, 0); + else if (class[i] == X86_64_INTEGERSI_CLASS) + tmpmode = SImode; + else + tmpmode = DImode; + /* We've requested 24 bytes we don't have mode for. Use DImode. */ + if (tmpmode == BLKmode) + tmpmode = DImode; + exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (tmpmode, *intreg), + GEN_INT (i*8)); + intreg++; + break; + case X86_64_SSESF_CLASS: + exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (SFmode, + SSE_REGNO (sse_regno)), + GEN_INT (i*8)); + sse_regno++; + break; + case X86_64_SSEDF_CLASS: + exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (DFmode, + SSE_REGNO (sse_regno)), + GEN_INT (i*8)); + sse_regno++; + break; + case X86_64_SSE_CLASS: + if (i < n && class[i + 1] == X86_64_SSEUP_CLASS) + tmpmode = TImode, i++; + else + tmpmode = DImode; + exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (tmpmode, + SSE_REGNO (sse_regno)), + GEN_INT (i*8)); + sse_regno++; + break; + default: + abort (); + } + } + ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nexps)); + for (i = 0; i < nexps; i++) + XVECEXP (ret, 0, i) = exp [i]; + return ret; +} + /* 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.) */ @@ -777,25 +2016,55 @@ function_arg_advance (cum, mode, type, named) 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 bytes = + (mode == BLKmode) ? int_size_in_bytes (type) : (int) 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) + if (TARGET_64BIT) { - cum->nregs = 0; - cum->regno = 0; + int int_nregs, sse_nregs; + if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs)) + cum->words += words; + else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs) + { + cum->nregs -= int_nregs; + cum->sse_nregs -= sse_nregs; + cum->regno += int_nregs; + cum->sse_regno += sse_nregs; + } + else + cum->words += words; } + else + { + if (TARGET_SSE && mode == TImode) + { + cum->sse_words += words; + cum->sse_nregs -= 1; + cum->sse_regno += 1; + if (cum->sse_nregs <= 0) + { + cum->sse_nregs = 0; + cum->sse_regno = 0; + } + } + else + { + cum->words += words; + cum->nregs -= words; + cum->regno += words; + if (cum->nregs <= 0) + { + cum->nregs = 0; + cum->regno = 0; + } + } + } return; } @@ -812,7 +2081,7 @@ function_arg_advance (cum, mode, type, named) NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). */ -struct rtx_def * +rtx function_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; /* current arg information */ enum machine_mode mode; /* current arg mode */ @@ -820,25 +2089,48 @@ function_arg (cum, mode, type, named) 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 bytes = + (mode == BLKmode) ? int_size_in_bytes (type) : (int) 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; + /* Handle an hidden AL argument containing number of registers for varargs + x86-64 functions. For i386 ABI just return constm1_rtx to avoid + any AL settings. */ + if (mode == VOIDmode) + { + if (TARGET_64BIT) + return GEN_INT (cum->maybe_vaarg + ? (cum->sse_nregs < 0 + ? SSE_REGPARM_MAX + : cum->sse_regno) + : -1); + else + return constm1_rtx; } + if (TARGET_64BIT) + ret = construct_container (mode, type, 0, cum->nregs, cum->sse_nregs, + &x86_64_int_parameter_registers [cum->regno], + cum->sse_regno); + else + 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; + case TImode: + if (cum->sse_nregs) + ret = gen_rtx_REG (mode, cum->sse_regno); + break; + } if (TARGET_DEBUG_ARG) { @@ -847,7 +2139,7 @@ function_arg (cum, mode, type, named) words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); if (ret) - fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]); + fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO (ret) ]); else fprintf (stderr, ", stack"); @@ -857,604 +2149,1352 @@ function_arg (cum, mode, type, named) 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. */ +/* Gives the alignment boundary, in bits, of an argument with the specified mode + and type. */ 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 */ +ix86_function_arg_boundary (mode, type) + enum machine_mode mode; + tree type; { - return 0; + int align; + if (!TARGET_64BIT) + return PARM_BOUNDARY; + if (type) + align = TYPE_ALIGN (type); + else + align = GET_MODE_ALIGNMENT (mode); + if (align < PARM_BOUNDARY) + align = PARM_BOUNDARY; + if (align > 128) + align = 128; + return align; } - -char * -singlemove_string (operands) - rtx *operands; + +/* Return true if N is a possible register number of function value. */ +bool +ix86_function_value_regno_p (regno) + int regno; { - 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 + if (!TARGET_64BIT) { - output_asm_insn ("push%L1 %1", operands); - return "pop%L0 %0"; + return ((regno) == 0 + || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387) + || ((regno) == FIRST_SSE_REG && TARGET_SSE)); } + return ((regno) == 0 || (regno) == FIRST_FLOAT_REG + || ((regno) == FIRST_SSE_REG && TARGET_SSE) + || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)); } - -/* Output an insn to add the constant N to the register X. */ -static void -asm_add (n, x) - int n; - rtx x; +/* 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. */ +rtx +ix86_function_value (valtype) + tree valtype; { - rtx xops[2]; - xops[0] = x; + if (TARGET_64BIT) + { + rtx ret = construct_container (TYPE_MODE (valtype), valtype, 1, + REGPARM_MAX, SSE_REGPARM_MAX, + x86_64_int_return_registers, 0); + /* For zero sized structures, construct_continer return NULL, but we need + to keep rest of compiler happy by returning meaningfull value. */ + if (!ret) + ret = gen_rtx_REG (TYPE_MODE (valtype), 0); + return ret; + } + else + return gen_rtx_REG (TYPE_MODE (valtype), VALUE_REGNO (TYPE_MODE (valtype))); +} - 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) +/* Return false iff type is returned in memory. */ +int +ix86_return_in_memory (type) + tree type; +{ + int needed_intregs, needed_sseregs; + if (TARGET_64BIT) { - xops[1] = GEN_INT (-n); - output_asm_insn (AS2 (sub%L0,%1,%0), xops); + return !examine_argument (TYPE_MODE (type), type, 1, + &needed_intregs, &needed_sseregs); } - else if (n > 0) + else { - xops[1] = GEN_INT (n); - output_asm_insn (AS2 (add%L0,%1,%0), xops); + if (TYPE_MODE (type) == BLKmode + || (VECTOR_MODE_P (TYPE_MODE (type)) + && int_size_in_bytes (type) == 8) + || (int_size_in_bytes (type) > 12 && TYPE_MODE (type) != TImode + && TYPE_MODE (type) != TFmode + && !VECTOR_MODE_P (TYPE_MODE (type)))) + return 1; + return 0; } } - -/* Output assembler code to perform a doubleword move insn - with operands OPERANDS. */ -char * -output_move_double (operands) - rtx *operands; +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ +rtx +ix86_libcall_value (mode) + enum machine_mode mode; { - 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; + if (TARGET_64BIT) + { + switch (mode) + { + case SFmode: + case SCmode: + case DFmode: + case DCmode: + return gen_rtx_REG (mode, FIRST_SSE_REG); + case TFmode: + case TCmode: + return gen_rtx_REG (mode, FIRST_FLOAT_REG); + default: + return gen_rtx_REG (mode, 0); + } + } else - optype1 = RNDOP; + return gen_rtx_REG (mode, VALUE_REGNO (mode)); +} + +/* Create the va_list data type. */ - /* 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. */ +tree +ix86_build_va_list () +{ + tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; + + /* For i386 we use plain pointer to argument area. */ + if (!TARGET_64BIT) + return build_pointer_type (char_type_node); + + record = make_lang_type (RECORD_TYPE); + type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); + + f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"), + unsigned_type_node); + f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"), + unsigned_type_node); + f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"), + ptr_type_node); + f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"), + ptr_type_node); + + DECL_FIELD_CONTEXT (f_gpr) = record; + DECL_FIELD_CONTEXT (f_fpr) = record; + DECL_FIELD_CONTEXT (f_ovf) = record; + DECL_FIELD_CONTEXT (f_sav) = record; + + TREE_CHAIN (record) = type_decl; + TYPE_NAME (record) = type_decl; + TYPE_FIELDS (record) = f_gpr; + TREE_CHAIN (f_gpr) = f_fpr; + TREE_CHAIN (f_fpr) = f_ovf; + TREE_CHAIN (f_ovf) = f_sav; + + layout_type (record); + + /* The correct type is an array type of one element. */ + return build_array_type (record, build_index_type (size_zero_node)); +} - if (optype0 == RNDOP || optype1 == RNDOP - || optype0 == MEMOP || optype1 == MEMOP) - abort (); +/* Perform any needed actions needed for a function that is receiving a + variable number of arguments. - /* If one operand is decrementing and one is incrementing - decrement the former register explicitly - and change that operand into ordinary indexing. */ + CUM is as above. - 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]); + MODE and TYPE are the mode and type of the current parameter. + + PRETEND_SIZE is a variable that should be set to the amount of stack + that must be pushed by the prolog to pretend that our caller pushed + it. + + Normally, this macro will push all remaining incoming registers on the + stack and set PRETEND_SIZE to the length of the registers pushed. */ + +void +ix86_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) + CUMULATIVE_ARGS *cum; + enum machine_mode mode; + tree type; + int *pretend_size ATTRIBUTE_UNUSED; + int no_rtl; + +{ + CUMULATIVE_ARGS next_cum; + rtx save_area = NULL_RTX, mem; + rtx label; + rtx label_ref; + rtx tmp_reg; + rtx nsse_reg; + int set; + tree fntype; + int stdarg_p; + int i; + + if (!TARGET_64BIT) + return; + + /* Indicate to allocate space on the stack for varargs save area. */ + ix86_save_varrargs_registers = 1; + + fntype = TREE_TYPE (current_function_decl); + stdarg_p = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + + /* For varargs, we do not want to skip the dummy va_dcl argument. + For stdargs, we do want to skip the last named argument. */ + next_cum = *cum; + if (stdarg_p) + function_arg_advance (&next_cum, mode, type, 1); + + if (!no_rtl) + save_area = frame_pointer_rtx; + + set = get_varargs_alias_set (); + + for (i = next_cum.regno; i < ix86_regparm; i++) + { + mem = gen_rtx_MEM (Pmode, + plus_constant (save_area, i * UNITS_PER_WORD)); + set_mem_alias_set (mem, set); + emit_move_insn (mem, gen_rtx_REG (Pmode, + x86_64_int_parameter_registers[i])); + } + + if (next_cum.sse_nregs) + { + /* Now emit code to save SSE registers. The AX parameter contains number + of SSE parameter regsiters used to call this function. We use + sse_prologue_save insn template that produces computed jump across + SSE saves. We need some preparation work to get this working. */ + + label = gen_label_rtx (); + label_ref = gen_rtx_LABEL_REF (Pmode, label); + + /* Compute address to jump to : + label - 5*eax + nnamed_sse_arguments*5 */ + tmp_reg = gen_reg_rtx (Pmode); + nsse_reg = gen_reg_rtx (Pmode); + emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0))); + emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, + gen_rtx_MULT (Pmode, nsse_reg, + GEN_INT (4)))); + if (next_cum.sse_regno) + emit_move_insn + (nsse_reg, + gen_rtx_CONST (DImode, + gen_rtx_PLUS (DImode, + label_ref, + GEN_INT (next_cum.sse_regno * 4)))); else - operands[0] = gen_rtx_MEM (DImode, operands[0]); - optype0 = OFFSOP; + emit_move_insn (nsse_reg, label_ref); + emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg)); + + /* Compute address of memory block we save into. We always use pointer + pointing 127 bytes after first byte to store - this is needed to keep + instruction size limited by 4 bytes. */ + tmp_reg = gen_reg_rtx (Pmode); + emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, + plus_constant (save_area, + 8 * REGPARM_MAX + 127))); + mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127)); + set_mem_alias_set (mem, set); + set_mem_align (mem, BITS_PER_WORD); + + /* And finally do the dirty job! */ + emit_insn (gen_sse_prologue_save (mem, nsse_reg, + GEN_INT (next_cum.sse_regno), label)); } - if (optype0 == POPOP && optype1 == PUSHOP) +} + +/* Implement va_start. */ + +void +ix86_va_start (stdarg_p, valist, nextarg) + int stdarg_p; + tree valist; + rtx nextarg; +{ + HOST_WIDE_INT words, n_gpr, n_fpr; + tree f_gpr, f_fpr, f_ovf, f_sav; + tree gpr, fpr, ovf, sav, t; + + /* Only 64bit target needs something special. */ + if (!TARGET_64BIT) { - /* ??? 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; + std_expand_builtin_va_start (stdarg_p, valist, nextarg); + return; } - /* 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. + f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_fpr = TREE_CHAIN (f_gpr); + f_ovf = TREE_CHAIN (f_fpr); + f_sav = TREE_CHAIN (f_ovf); + + valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); - 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. */ + /* Count number of gp and fp argument registers used. */ + words = current_function_args_info.words; + n_gpr = current_function_args_info.regno; + n_fpr = current_function_args_info.sse_regno; + + if (TARGET_DEBUG_ARG) + fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n", + (int) words, (int) n_gpr, (int) n_fpr); + + t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, + build_int_2 (n_gpr * 8, 0)); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, + build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0)); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Find the overflow area. */ + t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx); + if (words != 0) + t = build (PLUS_EXPR, TREE_TYPE (ovf), t, + build_int_2 (words * UNITS_PER_WORD, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + + /* Find the register save area. + Prologue of the function save it right above stack frame. */ + t = make_tree (TREE_TYPE (sav), frame_pointer_rtx); + t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); +} - if (size == 12) +/* Implement va_arg. */ +rtx +ix86_va_arg (valist, type) + tree valist, type; +{ + static int intreg[6] = { 0, 1, 2, 3, 4, 5 }; + tree f_gpr, f_fpr, f_ovf, f_sav; + tree gpr, fpr, ovf, sav, t; + int size, rsize; + rtx lab_false, lab_over = NULL_RTX; + rtx addr_rtx, r; + rtx container; + + /* Only 64bit target needs something special. */ + if (!TARGET_64BIT) { - if (optype0 == REGOP) + return std_expand_builtin_va_arg (valist, type); + } + + f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); + f_fpr = TREE_CHAIN (f_gpr); + f_ovf = TREE_CHAIN (f_fpr); + f_sav = TREE_CHAIN (f_ovf); + + valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist); + gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr); + fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr); + ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf); + sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav); + + size = int_size_in_bytes (type); + rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + + container = construct_container (TYPE_MODE (type), type, 0, + REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0); + /* + * Pull the value out of the saved registers ... + */ + + addr_rtx = gen_reg_rtx (Pmode); + + if (container) + { + rtx int_addr_rtx, sse_addr_rtx; + int needed_intregs, needed_sseregs; + int need_temp; + + lab_over = gen_label_rtx (); + lab_false = gen_label_rtx (); + + examine_argument (TYPE_MODE (type), type, 0, + &needed_intregs, &needed_sseregs); + + + need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64) + || TYPE_ALIGN (type) > 128); + + /* In case we are passing structure, verify that it is consetuctive block + on the register save area. If not we need to do moves. */ + if (!need_temp && !REG_P (container)) { - middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); - latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); + /* Verify that all registers are strictly consetuctive */ + if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0)))) + { + int i; + + for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) + { + rtx slot = XVECEXP (container, 0, i); + if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int) i + || INTVAL (XEXP (slot, 1)) != i * 16) + need_temp = 1; + } + } + else + { + int i; + + for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++) + { + rtx slot = XVECEXP (container, 0, i); + if (REGNO (XEXP (slot, 0)) != (unsigned int) i + || INTVAL (XEXP (slot, 1)) != i * 8) + need_temp = 1; + } + } } - else if (optype0 == OFFSOP) + if (!need_temp) { - middlehalf[0] = adj_offsettable_operand (operands[0], 4); - latehalf[0] = adj_offsettable_operand (operands[0], 8); + int_addr_rtx = addr_rtx; + sse_addr_rtx = addr_rtx; } else { - middlehalf[0] = operands[0]; - latehalf[0] = operands[0]; + int_addr_rtx = gen_reg_rtx (Pmode); + sse_addr_rtx = gen_reg_rtx (Pmode); + } + /* First ensure that we fit completely in registers. */ + if (needed_intregs) + { + emit_cmp_and_jump_insns (expand_expr + (gpr, NULL_RTX, SImode, EXPAND_NORMAL), + GEN_INT ((REGPARM_MAX - needed_intregs + + 1) * 8), GE, const1_rtx, SImode, + 1, lab_false); + } + if (needed_sseregs) + { + emit_cmp_and_jump_insns (expand_expr + (fpr, NULL_RTX, SImode, EXPAND_NORMAL), + GEN_INT ((SSE_REGPARM_MAX - + needed_sseregs + 1) * 16 + + REGPARM_MAX * 8), GE, const1_rtx, + SImode, 1, lab_false); } - if (optype1 == REGOP) + /* Compute index to start of area used for integer regs. */ + if (needed_intregs) { - middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); - latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); + t = build (PLUS_EXPR, ptr_type_node, sav, gpr); + r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL); + if (r != int_addr_rtx) + emit_move_insn (int_addr_rtx, r); } - else if (optype1 == OFFSOP) + if (needed_sseregs) { - middlehalf[1] = adj_offsettable_operand (operands[1], 4); - latehalf[1] = adj_offsettable_operand (operands[1], 8); + t = build (PLUS_EXPR, ptr_type_node, sav, fpr); + r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL); + if (r != sse_addr_rtx) + emit_move_insn (sse_addr_rtx, r); } - else if (optype1 == CNSTOP) + if (need_temp) { - if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - REAL_VALUE_TYPE r; long l[3]; + int i; + rtx mem; - 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]); + /* Never use the memory itself, as it has the alias set. */ + addr_rtx = XEXP (assign_temp (type, 0, 1, 0), 0); + mem = gen_rtx_MEM (BLKmode, addr_rtx); + set_mem_alias_set (mem, get_varargs_alias_set ()); + set_mem_align (mem, BITS_PER_UNIT); + + for (i = 0; i < XVECLEN (container, 0); i++) + { + rtx slot = XVECEXP (container, 0, i); + rtx reg = XEXP (slot, 0); + enum machine_mode mode = GET_MODE (reg); + rtx src_addr; + rtx src_mem; + int src_offset; + rtx dest_mem; + + if (SSE_REGNO_P (REGNO (reg))) + { + src_addr = sse_addr_rtx; + src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16; + } + else + { + src_addr = int_addr_rtx; + src_offset = REGNO (reg) * 8; + } + src_mem = gen_rtx_MEM (mode, src_addr); + set_mem_alias_set (src_mem, get_varargs_alias_set ()); + src_mem = adjust_address (src_mem, mode, src_offset); + dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1))); + emit_move_insn (dest_mem, src_mem); } - else if (CONSTANT_P (operands[1])) - /* No non-CONST_DOUBLE constant should ever appear here. */ - abort (); - } - else + } + + if (needed_intregs) + { + t = + build (PLUS_EXPR, TREE_TYPE (gpr), gpr, + build_int_2 (needed_intregs * 8, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } + if (needed_sseregs) { - middlehalf[1] = operands[1]; - latehalf[1] = operands[1]; + t = + build (PLUS_EXPR, TREE_TYPE (fpr), fpr, + build_int_2 (needed_sseregs * 16, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } + + emit_jump_insn (gen_jump (lab_over)); + emit_barrier (); + emit_label (lab_false); } + /* ... otherwise out of the overflow area. */ + + /* Care for on-stack alignment if needed. */ + if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64) + t = ovf; 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]; + HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8; + t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0)); + t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1)); } + t = save_expr (t); - /* 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); - } - } + r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL); + if (r != addr_rtx) + emit_move_insn (addr_rtx, r); - 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; + t = + build (PLUS_EXPR, TREE_TYPE (t), t, + build_int_2 (rsize * UNITS_PER_WORD, 0)); + t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - /* 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 ""; - } + if (container) + emit_label (lab_over); - 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; - } + return addr_rtx; +} + +/* Return nonzero if OP is general operand representable on x86_64. */ - /* If one or both operands autodecrementing, - do the two words, high-numbered first. */ +int +x86_64_general_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT) + return general_operand (op, mode); + if (nonimmediate_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op); +} - /* 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. */ +/* Return nonzero if OP is general operand representable on x86_64 + as either sign extended or zero extended constant. */ -#if 0 - if (optype0 == PUSHOP || optype1 == PUSHOP - || (optype0 == REGOP && optype1 == REGOP - && REGNO (operands[0]) == REGNO (latehalf[1])) - || dest_overlapped_low) -#endif +int +x86_64_szext_general_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT) + return general_operand (op, mode); + if (nonimmediate_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op) || x86_64_zero_extended_value (op); +} - 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); +/* Return nonzero if OP is nonmemory operand representable on x86_64. */ - if (size == 12) - output_asm_insn (singlemove_string (middlehalf), middlehalf); +int +x86_64_nonmemory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT) + return nonmemory_operand (op, mode); + if (register_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op); +} - /* Do low-numbered word. */ - return singlemove_string (operands); - } +/* Return nonzero if OP is nonmemory operand acceptable by movabs patterns. */ - /* Normal case: do the two words, low-numbered first. */ +int +x86_64_movabs_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT || !flag_pic) + return nonmemory_operand (op, mode); + if (register_operand (op, mode) || x86_64_sign_extended_value (op)) + return 1; + if (CONSTANT_P (op) && !symbolic_reference_mentioned_p (op)) + return 1; + return 0; +} - output_asm_insn (singlemove_string (operands), operands); +/* Return nonzero if OP is nonmemory operand representable on x86_64. */ - /* Do the middle one of the three words for long double */ - if (size == 12) - output_asm_insn (singlemove_string (middlehalf), middlehalf); +int +x86_64_szext_nonmemory_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT) + return nonmemory_operand (op, mode); + if (register_operand (op, mode)) + return 1; + return x86_64_sign_extended_value (op) || x86_64_zero_extended_value (op); +} - /* Do the high-numbered word. */ - output_asm_insn (singlemove_string (latehalf), latehalf); +/* Return nonzero if OP is immediate operand representable on x86_64. */ - return ""; +int +x86_64_immediate_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (!TARGET_64BIT) + return immediate_operand (op, mode); + return x86_64_sign_extended_value (op); } - -#define MAX_TMPS 2 /* max temporary registers used */ -/* Output the appropriate code to move push memory on the stack */ +/* Return nonzero if OP is immediate operand representable on x86_64. */ -char * -output_move_pushmem (operands, insn, length, tmp_start, n_operands) - rtx operands[]; - rtx insn; - int length; - int tmp_start; - int n_operands; +int +x86_64_zext_immediate_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; { - struct - { - char *load; - char *push; - rtx xops[2]; - } tmp_info[MAX_TMPS]; + return x86_64_zero_extended_value (op); +} - 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]; +/* Return nonzero if OP is (const_int 1), else return zero. */ - if (! offsettable_memref_p (src)) - fatal_insn ("Source is not offsettable", insn); +int +const_int_1_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == CONST_INT && INTVAL (op) == 1); +} - if ((length & 3) != 0) - fatal_insn ("Pushing non-word aligned size", insn); +/* Returns 1 if OP is either a symbol reference or a sum of a symbol + reference and a constant. */ - /* Figure out which temporary registers we have available */ - for (i = tmp_start; i < n_operands; i++) +int +symbolic_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + switch (GET_CODE (op)) { - if (GET_CODE (operands[i]) == REG) - { - if (reg_overlap_mentioned_p (operands[i], src)) - continue; + case SYMBOL_REF: + case LABEL_REF: + return 1; - tmp_info[ max_tmps++ ].xops[1] = operands[i]; - if (max_tmps == MAX_TMPS) - break; - } + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF + || (GET_CODE (op) == UNSPEC + && (XINT (op, 1) == 6 + || XINT (op, 1) == 7 + || XINT (op, 1) == 15))) + return 1; + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return 0; + + op = XEXP (op, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF) + return 1; + /* Only @GOTOFF gets offsets. */ + if (GET_CODE (op) != UNSPEC + || XINT (op, 1) != 7) + return 0; + + op = XVECEXP (op, 0, 0); + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF) + return 1; + return 0; + + default: + return 0; } +} - 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; - } +/* Return true if the operand contains a @GOT or @GOTOFF reference. */ - 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; - } +int +pic_symbolic_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) != CONST) + return 0; + op = XEXP (op, 0); + if (TARGET_64BIT) + { + if (GET_CODE (XEXP (op, 0)) == UNSPEC) + return 1; + } + else + { + if (GET_CODE (op) == UNSPEC) + return 1; + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return 0; + op = XEXP (op, 0); + if (GET_CODE (op) == UNSPEC) + return 1; + } + return 0; +} + +/* Return true if OP is a symbolic operand that resolves locally. */ + +static int +local_symbolic_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == LABEL_REF) + return 1; - for (i = 0; i < num_tmps; i++) - output_asm_insn (tmp_info[i].load, tmp_info[i].xops); + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) + op = XEXP (XEXP (op, 0), 0); - for (i = 0; i < num_tmps; i++) - output_asm_insn (tmp_info[i].push, tmp_info[i].xops); + if (GET_CODE (op) != SYMBOL_REF) + return 0; - if (stack_p) - stack_offset += 4*num_tmps; - } + /* These we've been told are local by varasm and encode_section_info + respectively. */ + if (CONSTANT_POOL_ADDRESS_P (op) || SYMBOL_REF_FLAG (op)) + return 1; - return ""; + /* There is, however, a not insubstantial body of code in the rest of + the compiler that assumes it can just stick the results of + ASM_GENERATE_INTERNAL_LABEL in a symbol_ref and have done. */ + /* ??? This is a hack. Should update the body of the compiler to + always create a DECL an invoke ENCODE_SECTION_INFO. */ + if (strncmp (XSTR (op, 0), internal_label_prefix, + internal_label_prefix_len) == 0) + return 1; + + return 0; } - + +/* Test for a valid operand for a call instruction. Don't allow the + arg pointer register or virtual regs since they may decay into + reg + const, which the patterns can't handle. */ + int -standard_80387_constant_p (x) - rtx x; +call_insn_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; { -#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) - REAL_VALUE_TYPE d; - jmp_buf handler; - int is0, is1; - - if (setjmp (handler)) + /* Disallow indirect through a virtual register. This leads to + compiler aborts when trying to eliminate them. */ + if (GET_CODE (op) == REG + && (op == arg_pointer_rtx + || op == frame_pointer_rtx + || (REGNO (op) >= FIRST_PSEUDO_REGISTER + && REGNO (op) <= LAST_VIRTUAL_REGISTER))) 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); + /* Disallow `call 1234'. Due to varying assembler lameness this + gets either rejected or translated to `call .+1234'. */ + if (GET_CODE (op) == CONST_INT) + return 0; - if (is0) + /* Explicitly allow SYMBOL_REF even if pic. */ + if (GET_CODE (op) == SYMBOL_REF) return 1; - if (is1) - return 2; + /* Half-pic doesn't allow anything but registers and constants. + We've just taken care of the later. */ + if (HALF_PIC_P ()) + return register_operand (op, Pmode); - /* 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 + /* Otherwise we can allow any general_operand in the address. */ + return general_operand (op, Pmode); +} - return 0; +int +constant_call_address_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) + op = XEXP (XEXP (op, 0), 0); + return GET_CODE (op) == SYMBOL_REF; } -char * -output_move_const_single (operands) - rtx *operands; +/* Match exactly zero and one. */ + +int +const0_operand (op, mode) + register rtx op; + enum machine_mode mode; { - if (FP_REG_P (operands[0])) - { - int conval = standard_80387_constant_p (operands[1]); + return op == CONST0_RTX (mode); +} + +int +const1_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return op == const1_rtx; +} + +/* Match 2, 4, or 8. Used for leal multiplicands. */ + +int +const248_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) == 2 || INTVAL (op) == 4 || INTVAL (op) == 8)); +} + +/* True if this is a constant appropriate for an increment or decremenmt. */ + +int +incdec_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + /* On Pentium4, the inc and dec operations causes extra dependency on flag + registers, since carry flag is not set. */ + if (TARGET_PENTIUM4 && !optimize_size) + return 0; + return op == const1_rtx || op == constm1_rtx; +} + +/* Return nonzero if OP is acceptable as operand of DImode shift + expander. */ + +int +shiftdi_operand (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + if (TARGET_64BIT) + return nonimmediate_operand (op, mode); + else + return register_operand (op, mode); +} + +/* Return false if this is the stack pointer, or any other fake + register eliminable to the stack pointer. Otherwise, this is + a register operand. + + This is used to prevent esp from being used as an index reg. + Which would only happen in pathological cases. */ + +int +reg_no_sp_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == stack_pointer_rtx || t == arg_pointer_rtx || t == frame_pointer_rtx) + return 0; + + return register_operand (op, mode); +} + +int +mmx_reg_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return MMX_REG_P (op); +} + +/* Return false if this is any eliminable register. Otherwise + general_operand. */ + +int +general_no_elim_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == arg_pointer_rtx || t == frame_pointer_rtx + || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx + || t == virtual_stack_dynamic_rtx) + return 0; + if (REG_P (t) + && REGNO (t) >= FIRST_VIRTUAL_REGISTER + && REGNO (t) <= LAST_VIRTUAL_REGISTER) + return 0; + + return general_operand (op, mode); +} + +/* Return false if this is any eliminable register. Otherwise + register_operand or const_int. */ + +int +nonmemory_no_elim_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + rtx t = op; + if (GET_CODE (t) == SUBREG) + t = SUBREG_REG (t); + if (t == arg_pointer_rtx || t == frame_pointer_rtx + || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx + || t == virtual_stack_dynamic_rtx) + return 0; + + return GET_CODE (op) == CONST_INT || register_operand (op, mode); +} + +/* Return true if op is a Q_REGS class register. */ - if (conval == 1) - return "fldz"; +int +q_regs_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return QI_REG_P (op); +} + +/* Return true if op is a NON_Q_REGS class register. */ + +int +non_q_regs_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return NON_QI_REG_P (op); +} - if (conval == 2) - return "fld1"; +/* Return 1 if OP is a comparison that can be used in the CMPSS/CMPPS + insns. */ +int +sse_comparison_operator (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + enum rtx_code code = GET_CODE (op); + switch (code) + { + /* Operations supported directly. */ + case EQ: + case LT: + case LE: + case UNORDERED: + case NE: + case UNGE: + case UNGT: + case ORDERED: + return 1; + /* These are equivalent to ones above in non-IEEE comparisons. */ + case UNEQ: + case UNLT: + case UNLE: + case LTGT: + case GE: + case GT: + return !TARGET_IEEE_FP; + default: + return 0; } +} +/* Return 1 if OP is a valid comparison operator in valid mode. */ +int +ix86_comparison_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + enum machine_mode inmode; + enum rtx_code code = GET_CODE (op); + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_RTX_CLASS (code) != '<') + return 0; + inmode = GET_MODE (XEXP (op, 0)); - if (GET_CODE (operands[1]) == CONST_DOUBLE) + if (inmode == CCFPmode || inmode == CCFPUmode) + { + enum rtx_code second_code, bypass_code; + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + return (bypass_code == NIL && second_code == NIL); + } + switch (code) { - REAL_VALUE_TYPE r; long l; + case EQ: case NE: + return 1; + case LT: case GE: + if (inmode == CCmode || inmode == CCGCmode + || inmode == CCGOCmode || inmode == CCNOmode) + return 1; + return 0; + case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU: + if (inmode == CCmode) + return 1; + return 0; + case GT: case LE: + if (inmode == CCmode || inmode == CCGCmode || inmode == CCNOmode) + return 1; + return 0; + default: + return 0; + } +} - if (GET_MODE (operands[1]) == XFmode) - abort (); +/* Return 1 if OP is a comparison operator that can be issued by fcmov. */ - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); - REAL_VALUE_TO_TARGET_SINGLE (r, l); - operands[1] = GEN_INT (l); +int +fcmov_comparison_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + enum machine_mode inmode; + enum rtx_code code = GET_CODE (op); + if (mode != VOIDmode && GET_MODE (op) != mode) + return 0; + if (GET_RTX_CLASS (code) != '<') + return 0; + inmode = GET_MODE (XEXP (op, 0)); + if (inmode == CCFPmode || inmode == CCFPUmode) + { + enum rtx_code second_code, bypass_code; + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + if (bypass_code != NIL || second_code != NIL) + return 0; + code = ix86_fp_compare_code_to_integer (code); + } + /* i387 supports just limited amount of conditional codes. */ + switch (code) + { + case LTU: case GTU: case LEU: case GEU: + if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode) + return 1; + return 0; + case ORDERED: case UNORDERED: + case EQ: case NE: + return 1; + default: + return 0; } - - return singlemove_string (operands); } - -/* Returns 1 if OP is either a symbol reference or a sum of a symbol - reference and a constant. */ + +/* Return 1 if OP is a binary operator that can be promoted to wider mode. */ int -symbolic_operand (op, mode) +promotable_binary_operator (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { switch (GET_CODE (op)) { - case SYMBOL_REF: - case LABEL_REF: + case MULT: + /* Modern CPUs have same latency for HImode and SImode multiply, + but 386 and 486 do HImode multiply faster. */ + return ix86_cpu > PROCESSOR_I486; + case PLUS: + case AND: + case IOR: + case XOR: + case ASHIFT: return 1; + default: + return 0; + } +} - 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); +/* Nearly general operand, but accept any const_double, since we wish + to be able to drop them into memory rather than have them get pulled + into registers. */ + +int +cmp_fp_expander_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + if (mode != VOIDmode && mode != GET_MODE (op)) + return 0; + if (GET_CODE (op) == CONST_DOUBLE) + return 1; + return general_operand (op, mode); +} + +/* Match an SI or HImode register for a zero_extract. */ + +int +ext_register_operand (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + int regno; + if ((!TARGET_64BIT || GET_MODE (op) != DImode) + && GET_MODE (op) != SImode && GET_MODE (op) != HImode) + return 0; + + if (!register_operand (op, VOIDmode)) + return 0; + + /* Be curefull to accept only registers having upper parts. */ + regno = REG_P (op) ? REGNO (op) : REGNO (SUBREG_REG (op)); + return (regno > LAST_VIRTUAL_REGISTER || regno < 4); +} + +/* Return 1 if this is a valid binary floating-point operation. + OP is the expression matched, and MODE is its mode. */ + +int +binary_fp_operator (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 nonzero if OP is a constant shift count small enough to - encode into an lea instruction. */ +int +mult_operator (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return GET_CODE (op) == MULT; +} + +int +div_operator (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return GET_CODE (op) == DIV; +} int -small_shift_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +arith_or_logical_operator (op, mode) + rtx op; + enum machine_mode mode; { - return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4); + return ((mode == VOIDmode || GET_MODE (op) == mode) + && (GET_RTX_CLASS (GET_CODE (op)) == 'c' + || GET_RTX_CLASS (GET_CODE (op)) == '2')); } -/* 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. */ +/* Returns 1 if OP is memory operand with a displacement. */ int -call_insn_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +memory_displacement_operand (op, mode) + register rtx op; + enum machine_mode mode; { - 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; + struct ix86_address parts; - return 0; + if (! memory_operand (op, mode)) + return 0; + + if (! ix86_decompose_address (XEXP (op, 0), &parts)) + abort (); + + return parts.disp != NULL_RTX; } -/* Like call_insn_operand but allow (mem (symbol_ref ...)) - even if pic. */ +/* To avoid problems when jump re-emits comparisons like testqi_ext_ccno_0, + re-recognize the operand to avoid a copy_to_mode_reg that will fail. + + ??? It seems likely that this will only work because cmpsi is an + expander, and no actual insns use this. */ int -expander_call_insn_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +cmpsi_operand (op, mode) + rtx op; + enum machine_mode mode; { - 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)))) + if (nonimmediate_operand (op, mode)) + return 1; + + if (GET_CODE (op) == AND + && GET_MODE (op) == SImode + && GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT + && GET_CODE (XEXP (XEXP (op, 0), 2)) == CONST_INT + && INTVAL (XEXP (XEXP (op, 0), 1)) == 8 + && INTVAL (XEXP (XEXP (op, 0), 2)) == 8 + && GET_CODE (XEXP (op, 1)) == CONST_INT) return 1; return 0; } -/* Return 1 if OP is a comparison operator that can use the condition code - generated by an arithmetic operation. */ +/* Returns 1 if OP is memory operand that can not be represented by the + modRM array. */ int -arithmetic_comparison_operator (op, mode) +long_memory_operand (op, mode) register rtx op; enum machine_mode mode; { - enum rtx_code code; + if (! memory_operand (op, mode)) + return 0; - if (mode != VOIDmode && mode != GET_MODE (op)) + return memory_address_length (op) != 0; +} + +/* Return nonzero if the rtx is known aligned. */ + +int +aligned_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + struct ix86_address parts; + + if (!general_operand (op, mode)) return 0; - code = GET_CODE (op); - if (GET_RTX_CLASS (code) != '<') + /* 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; - return (code != GT && code != LE); + op = XEXP (op, 0); + + /* Pushes and pops are only valid on the stack pointer. */ + if (GET_CODE (op) == PRE_DEC + || GET_CODE (op) == POST_INC) + return 1; + + /* Decode the address. */ + if (! ix86_decompose_address (op, &parts)) + abort (); + + /* Look for some component that isn't known to be aligned. */ + if (parts.index) + { + if (parts.scale < 4 + && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 32) + return 0; + } + if (parts.base) + { + if (REGNO_POINTER_ALIGN (REGNO (parts.base)) < 32) + return 0; + } + if (parts.disp) + { + if (GET_CODE (parts.disp) != CONST_INT + || (INTVAL (parts.disp) & 3) != 0) + return 0; + } + + /* Didn't find one -- this must be an aligned address. */ + return 1; } + +/* Return true if the constant is something that can be loaded with + a special instruction. Only handle 0.0 and 1.0; others are less + worthwhile. */ int -ix86_logical_operator (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +standard_80387_constant_p (x) + rtx x; { - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR; + if (GET_CODE (x) != CONST_DOUBLE || !FLOAT_MODE_P (GET_MODE (x))) + return -1; + /* Note that on the 80387, other constants, such as pi, that we should support + too. On some machines, these are much slower to load as standard constant, + than to load from doubles in memory. */ + if (x == CONST0_RTX (GET_MODE (x))) + return 1; + if (x == CONST1_RTX (GET_MODE (x))) + return 2; + return 0; +} + +/* Return 1 if X is FP constant we can load to SSE register w/o using memory. + */ +int +standard_sse_constant_p (x) + rtx x; +{ + if (GET_CODE (x) != CONST_DOUBLE) + return -1; + return (x == CONST0_RTX (GET_MODE (x))); } - /* Returns 1 if OP contains a symbol reference */ int symbolic_reference_mentioned_p (op) rtx op; { - register char *fmt; + register const char *fmt; register int i; if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) @@ -1478,834 +3518,1131 @@ symbolic_reference_mentioned_p (op) 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. */ + +/* 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_expand_binary_operator (code, mode, operands) - enum rtx_code code; - enum machine_mode mode; - rtx operands[]; +ix86_can_use_return_insn_p () { - int modified; + struct ix86_frame frame; - /* 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; - } +#ifdef NON_SAVING_SETJMP + if (NON_SAVING_SETJMP && current_function_calls_setjmp) + return 0; +#endif - /* 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 (! reload_completed || frame_pointer_needed) + return 0; - if (GET_CODE (operands[2]) == MEM) - operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + /* Don't allow more than 32 pop, since that's all we can do + with one instruction. */ + if (current_function_pops_args + && current_function_args_size >= 32768) + return 0; - if (GET_CODE (operands[1]) == CONST_INT && code == MINUS) - { - rtx temp = gen_reg_rtx (GET_MODE (operands[0])); + ix86_compute_frame_layout (&frame); + return frame.to_allocate == 0 && frame.nregs == 0; +} + +/* Return 1 if VALUE can be stored in the sign extended immediate field. */ +int +x86_64_sign_extended_value (value) + rtx value; +{ + switch (GET_CODE (value)) + { + /* CONST_DOUBLES never match, since HOST_BITS_PER_WIDE_INT is known + to be at least 32 and this all acceptable constants are + represented as CONST_INT. */ + case CONST_INT: + if (HOST_BITS_PER_WIDE_INT == 32) + return 1; + else + { + HOST_WIDE_INT val = trunc_int_for_mode (INTVAL (value), DImode); + return trunc_int_for_mode (val, SImode) == val; + } + break; - emit_move_insn (temp, operands[1]); - operands[1] = temp; - return TRUE; - } + /* For certain code models, the symbolic references are known to fit. */ + case SYMBOL_REF: + return ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL; + + /* For certain code models, the code is near as well. */ + case LABEL_REF: + return ix86_cmodel != CM_LARGE && ix86_cmodel != CM_SMALL_PIC; + + /* We also may accept the offsetted memory references in certain special + cases. */ + case CONST: + if (GET_CODE (XEXP (value, 0)) == UNSPEC + && XVECLEN (XEXP (value, 0), 0) == 1 + && XINT (XEXP (value, 0), 1) == 15) + return 1; + else if (GET_CODE (XEXP (value, 0)) == PLUS) + { + rtx op1 = XEXP (XEXP (value, 0), 0); + rtx op2 = XEXP (XEXP (value, 0), 1); + HOST_WIDE_INT offset; + + if (ix86_cmodel == CM_LARGE) + return 0; + if (GET_CODE (op2) != CONST_INT) + return 0; + offset = trunc_int_for_mode (INTVAL (op2), DImode); + switch (GET_CODE (op1)) + { + case SYMBOL_REF: + /* For CM_SMALL assume that latest object is 1MB before + end of 31bits boundary. We may also accept pretty + large negative constants knowing that all objects are + in the positive half of address space. */ + if (ix86_cmodel == CM_SMALL + && offset < 1024*1024*1024 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + /* For CM_KERNEL we know that all object resist in the + negative half of 32bits address space. We may not + accept negative offsets, since they may be just off + and we may accept pretty large positive ones. */ + if (ix86_cmodel == CM_KERNEL + && offset > 0 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + break; + case LABEL_REF: + /* These conditions are similar to SYMBOL_REF ones, just the + constraints for code models differ. */ + if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM) + && offset < 1024*1024*1024 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + if (ix86_cmodel == CM_KERNEL + && offset > 0 + && trunc_int_for_mode (offset, SImode) == offset) + return 1; + break; + default: + return 0; + } + } + return 0; + default: + return 0; } +} - if (!ix86_binary_operator_ok (code, mode, operands)) +/* Return 1 if VALUE can be stored in the zero extended immediate field. */ +int +x86_64_zero_extended_value (value) + rtx value; +{ + switch (GET_CODE (value)) { - /* 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; - } + case CONST_DOUBLE: + if (HOST_BITS_PER_WIDE_INT == 32) + return (GET_MODE (value) == VOIDmode + && !CONST_DOUBLE_HIGH (value)); + else + return 0; + case CONST_INT: + if (HOST_BITS_PER_WIDE_INT == 32) + return INTVAL (value) >= 0; + else + return !(INTVAL (value) & ~(HOST_WIDE_INT) 0xffffffff); + break; - if (GET_CODE (operands[2]) == MEM) - { - operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); - modified = TRUE; - } + /* For certain code models, the symbolic references are known to fit. */ + case SYMBOL_REF: + return ix86_cmodel == CM_SMALL; - if (GET_CODE (operands[1]) == CONST_INT && code == MINUS) - { - rtx temp = gen_reg_rtx (GET_MODE (operands[0])); + /* For certain code models, the code is near as well. */ + case LABEL_REF: + return ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM; - emit_move_insn (temp, operands[1]); - operands[1] = temp; - return TRUE; - } + /* We also may accept the offsetted memory references in certain special + cases. */ + case CONST: + if (GET_CODE (XEXP (value, 0)) == PLUS) + { + rtx op1 = XEXP (XEXP (value, 0), 0); + rtx op2 = XEXP (XEXP (value, 0), 1); - if (modified && ! ix86_binary_operator_ok (code, mode, operands)) - return FALSE; - } - else - return FALSE; + if (ix86_cmodel == CM_LARGE) + return 0; + switch (GET_CODE (op1)) + { + case SYMBOL_REF: + return 0; + /* For small code model we may accept pretty large positive + offsets, since one bit is available for free. Negative + offsets are limited by the size of NULL pointer area + specified by the ABI. */ + if (ix86_cmodel == CM_SMALL + && GET_CODE (op2) == CONST_INT + && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000 + && (trunc_int_for_mode (INTVAL (op2), SImode) + == INTVAL (op2))) + return 1; + /* ??? For the kernel, we may accept adjustment of + -0x10000000, since we know that it will just convert + negative address space to positive, but perhaps this + is not worthwhile. */ + break; + case LABEL_REF: + /* These conditions are similar to SYMBOL_REF ones, just the + constraints for code models differ. */ + if ((ix86_cmodel == CM_SMALL || ix86_cmodel == CM_MEDIUM) + && GET_CODE (op2) == CONST_INT + && trunc_int_for_mode (INTVAL (op2), DImode) > -0x10000 + && (trunc_int_for_mode (INTVAL (op2), SImode) + == INTVAL (op2))) + return 1; + break; + default: + return 0; + } + } + return 0; + default: + return 0; } - - 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. */ +/* 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. */ int -ix86_expand_unary_operator (code, mode, operands) - enum rtx_code code; - enum machine_mode mode; - rtx operands[]; +ix86_frame_pointer_required () { - /* 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 we accessed previous frames, then the generated code expects + to be able to access the saved ebp value in our frame. */ + if (cfun->machine->accesses_prev_frame) + return 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; - } + /* Several x86 os'es need a frame pointer for other reasons, + usually pertaining to setjmp. */ + if (SUBTARGET_FRAME_POINTER_REQUIRED) + return 1; - return TRUE; + /* In override_options, TARGET_OMIT_LEAF_FRAME_POINTER turns off + the frame pointer by default. Turn it back on now if we've not + got a leaf function. */ + if (TARGET_OMIT_LEAF_FRAME_POINTER && ! leaf_function_p ()) + return 1; + + return 0; } - -/* 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; +/* Record that the current function accesses previous call frames. */ + +void +ix86_setup_frame_addresses () { - return TRUE; + cfun->machine->accesses_prev_frame = 1; } -static rtx pic_label_rtx; -static char pic_label_name [256]; -static int pic_label_no = 0; +static char pic_label_name[32]; /* 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) +ix86_asm_file_end (file) 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; - } + if (! TARGET_DEEP_BRANCH_PREDICTION || pic_label_name[0] == 0) + return; - prologue_node = make_node (FUNCTION_DECL); - DECL_RESULT (prologue_node) = 0; + /* ??? Binutils 2.10 and earlier has a linkonce elimination bug related + to updating relocations to a section being discarded such that this + doesn't work. Ought to detect this at configure time. */ +#if 0 + /* The trick here is to create a linkonce section containing the + pic label thunk, but to refer to it with an internal label. + Because the label is internal, we don't have inter-dso name + binding issues on hosts that don't support ".hidden". + + In order to use these macros, however, we must create a fake + function decl. */ + if (targetm.have_named_sections) + { + tree decl = build_decl (FUNCTION_DECL, + get_identifier ("i686.get_pc_thunk"), + error_mark_node); + DECL_ONE_ONLY (decl) = 1; + UNIQUE_SECTION (decl, 0); + named_section (decl, NULL); + } + else +#else + text_section (); +#endif - /* 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. */ + /* 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); - ASM_OUTPUT_LABEL (file, pic_label_name); - output_asm_insn ("movl (%1),%0", xops); - output_asm_insn ("ret", xops); - } + xops[0] = pic_offset_table_rtx; + xops[1] = gen_rtx_MEM (SImode, stack_pointer_rtx); + output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", 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; +load_pic_register () { - if (TARGET_SCHEDULE_PROLOGUE) + rtx gotsym, pclab; + + if (TARGET_64BIT) + abort (); + + gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + + if (TARGET_DEEP_BRANCH_PREDICTION) { - pic_label_rtx = 0; - return; + if (! pic_label_name[0]) + ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0); + pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name)); } + else + { + pclab = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); + } + + emit_insn (gen_prologue_get_pc (pic_offset_table_rtx, pclab)); + + if (! TARGET_DEEP_BRANCH_PREDICTION) + emit_insn (gen_popsi1 (pic_offset_table_rtx)); - ix86_prologue (0); + emit_insn (gen_prologue_set_got (pic_offset_table_rtx, gotsym, pclab)); } -/* Expand the prologue into a bunch of separate insns. */ +/* Generate an "push" pattern for input ARG. */ -void -ix86_expand_prologue () +static rtx +gen_push (arg) + rtx arg; { - if (! TARGET_SCHEDULE_PROLOGUE) - return; - - ix86_prologue (1); + return gen_rtx_SET (VOIDmode, + gen_rtx_MEM (Pmode, + gen_rtx_PRE_DEC (Pmode, + stack_pointer_rtx)), + arg); } -void -load_pic_register (do_rtl) - int do_rtl; +/* Return 1 if we need to save REGNO. */ +static int +ix86_save_reg (regno, maybe_eh_return) + int regno; + int maybe_eh_return; { - rtx xops[4]; + if (flag_pic + && ! TARGET_64BIT + && regno == PIC_OFFSET_TABLE_REGNUM + && (current_function_uses_pic_offset_table + || current_function_uses_const_pool + || current_function_calls_eh_return)) + return 1; - if (TARGET_DEEP_BRANCH_PREDICTION) + if (current_function_calls_eh_return && maybe_eh_return) { - xops[0] = pic_offset_table_rtx; - if (pic_label_rtx == 0) + unsigned i; + for (i = 0; ; i++) { - 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; + unsigned test = EH_RETURN_DATA_REGNO (i); + if (test == INVALID_REGNUM) + break; + if (test == (unsigned) regno) + return 1; } + } - xops[1] = gen_rtx_MEM (QImode, - gen_rtx (SYMBOL_REF, Pmode, - LABEL_NAME (pic_label_rtx))); + return (regs_ever_live[regno] + && !call_used_regs[regno] + && !fixed_regs[regno] + && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed)); +} - 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; - } - } +/* Return number of registers to be saved on the stack. */ + +static int +ix86_nsaved_regs () +{ + int nregs = 0; + int regno; + for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) + if (ix86_save_reg (regno, true)) + nregs++; + return nregs; +} + +/* Return the offset between two registers, one to be eliminated, and the other + its replacement, at the start of a routine. */ + +HOST_WIDE_INT +ix86_initial_elimination_offset (from, to) + int from; + int to; +{ + struct ix86_frame frame; + ix86_compute_frame_layout (&frame); + + if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) + return frame.hard_frame_pointer_offset; + else if (from == FRAME_POINTER_REGNUM + && to == HARD_FRAME_POINTER_REGNUM) + return frame.hard_frame_pointer_offset - frame.frame_pointer_offset; 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])); - } + if (to != STACK_POINTER_REGNUM) + abort (); + else if (from == ARG_POINTER_REGNUM) + return frame.stack_pointer_offset; + else if (from != FRAME_POINTER_REGNUM) + abort (); 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); - } + return frame.stack_pointer_offset - frame.frame_pointer_offset; } - - /* 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. */ +/* Fill structure ix86_frame about frame of currently computed function. */ -HOST_WIDE_INT -ix86_compute_frame_size (size, nregs_on_stack) - HOST_WIDE_INT size; - int *nregs_on_stack; +static void +ix86_compute_frame_layout (frame) + struct ix86_frame *frame; { - 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; + int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT; + int offset; + int preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT; + HOST_WIDE_INT size = get_frame_size (); - limit = frame_pointer_needed - ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; + frame->nregs = ix86_nsaved_regs (); + total_size = size; - nregs = 0; + /* Skip return value and save base pointer. */ + offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD; - 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++; + frame->hard_frame_pointer_offset = offset; - padding = 0; - total_size = size + (nregs * UNITS_PER_WORD); + /* Do some sanity checking of stack_alignment_needed and + preferred_alignment, since i386 port is the only using those features + that may break easily. */ -#ifdef PREFERRED_STACK_BOUNDARY - { - int offset; - int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; + if (size && !stack_alignment_needed) + abort (); + if (preferred_alignment < STACK_BOUNDARY / BITS_PER_UNIT) + abort (); + if (preferred_alignment > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) + abort (); + if (stack_alignment_needed > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) + abort (); - offset = 4; - if (frame_pointer_needed) - offset += UNITS_PER_WORD; + if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT) + stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT; - total_size += offset; - - padding = ((total_size + preferred_alignment - 1) - & -preferred_alignment) - total_size; + /* Register save area */ + offset += frame->nregs * UNITS_PER_WORD; - if (padding < (((offset + preferred_alignment - 1) - & -preferred_alignment) - offset)) - padding += preferred_alignment; + /* Va-arg area */ + if (ix86_save_varrargs_registers) + { + offset += X86_64_VARARGS_SIZE; + frame->va_arg_size = X86_64_VARARGS_SIZE; + } + else + frame->va_arg_size = 0; - /* 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 + /* Align start of frame for local function. */ + frame->padding1 = ((offset + stack_alignment_needed - 1) + & -stack_alignment_needed) - offset; - if (nregs_on_stack) - *nregs_on_stack = nregs; + offset += frame->padding1; - return size + padding; + /* Frame pointer points here. */ + frame->frame_pointer_offset = offset; + + offset += size; + + /* Add outgoing arguments area. */ + if (ACCUMULATE_OUTGOING_ARGS) + { + offset += current_function_outgoing_args_size; + frame->outgoing_arguments_size = current_function_outgoing_args_size; + } + else + frame->outgoing_arguments_size = 0; + + /* Align stack boundary. */ + frame->padding2 = ((offset + preferred_alignment - 1) + & -preferred_alignment) - offset; + + offset += frame->padding2; + + /* We've reached end of stack frame. */ + frame->stack_pointer_offset = offset; + + /* Size prologue needs to allocate. */ + frame->to_allocate = + (size + frame->padding1 + frame->padding2 + + frame->outgoing_arguments_size + frame->va_arg_size); + + if (TARGET_64BIT && TARGET_RED_ZONE && current_function_sp_is_unchanging + && current_function_is_leaf) + { + frame->red_zone_size = frame->to_allocate; + if (frame->red_zone_size > RED_ZONE_SIZE - RED_ZONE_RESERVE) + frame->red_zone_size = RED_ZONE_SIZE - RED_ZONE_RESERVE; + } + else + frame->red_zone_size = 0; + frame->to_allocate -= frame->red_zone_size; + frame->stack_pointer_offset -= frame->red_zone_size; +#if 0 + fprintf (stderr, "nregs: %i\n", frame->nregs); + fprintf (stderr, "size: %i\n", size); + fprintf (stderr, "alignment1: %i\n", stack_alignment_needed); + fprintf (stderr, "padding1: %i\n", frame->padding1); + fprintf (stderr, "va_arg: %i\n", frame->va_arg_size); + fprintf (stderr, "padding2: %i\n", frame->padding2); + fprintf (stderr, "to_allocate: %i\n", frame->to_allocate); + fprintf (stderr, "red_zone_size: %i\n", frame->red_zone_size); + fprintf (stderr, "frame_pointer_offset: %i\n", frame->frame_pointer_offset); + fprintf (stderr, "hard_frame_pointer_offset: %i\n", + frame->hard_frame_pointer_offset); + fprintf (stderr, "stack_pointer_offset: %i\n", frame->stack_pointer_offset); +#endif } +/* Emit code to save registers in the prologue. */ + static void -ix86_prologue (do_rtl) - int do_rtl; +ix86_emit_save_regs () { 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); + for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) + if (ix86_save_reg (regno, true)) + { + insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno))); + RTX_FRAME_RELATED_P (insn) = 1; + } +} + +/* Emit code to save registers using MOV insns. First register + is restored from POINTER + OFFSET. */ +static void +ix86_emit_save_regs_using_mov (pointer, offset) + rtx pointer; + HOST_WIDE_INT offset; +{ + int regno; + rtx insn; + + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (ix86_save_reg (regno, true)) + { + insn = emit_move_insn (adjust_address (gen_rtx_MEM (Pmode, pointer), + Pmode, offset), + gen_rtx_REG (Pmode, regno)); + RTX_FRAME_RELATED_P (insn) = 1; + offset += UNITS_PER_WORD; + } +} - if (frame_pointer_needed) +/* Expand the prologue into a bunch of separate insns. */ + +void +ix86_expand_prologue () +{ + rtx insn; + int pic_reg_used = (flag_pic && (current_function_uses_pic_offset_table + || current_function_uses_const_pool) + && !TARGET_64BIT); + struct ix86_frame frame; + int use_mov = 0; + HOST_WIDE_INT allocate; + + if (!optimize_size) { - 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)); + use_fast_prologue_epilogue + = !expensive_function_p (FAST_PROLOGUE_INSN_COUNT); + if (TARGET_PROLOGUE_USING_MOVE) + use_mov = use_fast_prologue_epilogue; + } + ix86_compute_frame_layout (&frame); - RTX_FRAME_RELATED_P (insn) = 1; - insn = emit_move_insn (xops[1], xops[0]); - RTX_FRAME_RELATED_P (insn) = 1; - } + /* Note: AT&T enter does NOT have reversed args. Enter is probably + slower on all targets. Also sdb doesn't like it. */ - 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 + if (frame_pointer_needed) + { + insn = emit_insn (gen_push (hard_frame_pointer_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; - 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 - } + insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; } - if (tsize == 0) + allocate = frame.to_allocate; + /* In case we are dealing only with single register and empty frame, + push is equivalent of the mov+add sequence. */ + if (allocate == 0 && frame.nregs <= 1) + use_mov = 0; + + if (!use_mov) + ix86_emit_save_regs (); + else + allocate += frame.nregs * UNITS_PER_WORD; + + if (allocate == 0) ; - else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT) + else if (! TARGET_STACK_PROBE || allocate < 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 - } + insn = emit_insn (gen_pro_epilogue_adjust_stack + (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-allocate))); + RTX_FRAME_RELATED_P (insn) = 1; } 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); + /* ??? Is this only valid for Win32? */ - xops[3] = gen_rtx_MEM (FUNCTION_MODE, - gen_rtx (SYMBOL_REF, Pmode, "_alloca")); + rtx arg0, sym; - if (do_rtl) - emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx)); - else - output_asm_insn (AS1 (call,%P3), xops); - } + if (TARGET_64BIT) + abort (); - /* 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); - } - */ + arg0 = gen_rtx_REG (SImode, 0); + emit_move_insn (arg0, GEN_INT (allocate)); - 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])); + sym = gen_rtx_MEM (FUNCTION_MODE, + gen_rtx_SYMBOL_REF (Pmode, "_alloca")); + insn = emit_call_insn (gen_call (sym, const0_rtx, constm1_rtx)); - 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 - } - } + CALL_INSN_FUNCTION_USAGE (insn) + = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, arg0), + CALL_INSN_FUNCTION_USAGE (insn)); + } + if (use_mov) + { + if (!frame_pointer_needed || !frame.to_allocate) + ix86_emit_save_regs_using_mov (stack_pointer_rtx, frame.to_allocate); + else + ix86_emit_save_regs_using_mov (hard_frame_pointer_rtx, + -frame.nregs * UNITS_PER_WORD); + } #ifdef SUBTARGET_PROLOGUE SUBTARGET_PROLOGUE; -#endif +#endif if (pic_reg_used) - load_pic_register (do_rtl); + load_pic_register (); /* 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) + if (current_function_profile && ! pic_reg_used) 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 () +/* Emit code to restore saved registers using MOV insns. First register + is restored from POINTER + OFFSET. */ +static void +ix86_emit_restore_regs_using_mov (pointer, offset, maybe_eh_return) + rtx pointer; + int offset; + int maybe_eh_return; { 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; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (ix86_save_reg (regno, maybe_eh_return)) + { + emit_move_insn (gen_rtx_REG (Pmode, regno), + adjust_address (gen_rtx_MEM (Pmode, pointer), + Pmode, offset)); + offset += UNITS_PER_WORD; + } } -/* Restore function stack, frame, and registers. */ +/* Restore function stack, frame, and registers. */ void -ix86_expand_epilogue () -{ - ix86_epilogue (1); -} - -static void -ix86_epilogue (do_rtl) - int do_rtl; +ix86_expand_epilogue (style) + int style; { - 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 regno; int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; + struct ix86_frame frame; 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. + ix86_compute_frame_layout (&frame); - 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 ()); + /* Calculate start of saved registers relative to ebp. Special care + must be taken for the normal return case of a function using + eh_return: the eax and edx registers are marked as saved, but not + restored along this path. */ + offset = frame.nregs; + if (current_function_calls_eh_return && style != 2) + offset -= 2; + offset *= -UNITS_PER_WORD; /* 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. */ + less work than reloading sp and popping the register. + + The default code result in stack adjustment using add/lea instruction, + while this code results in LEAVE instruction (or discrete equivalent), + so it is profitable in some other cases as well. Especially when there + are no registers to restore. We also use this code when TARGET_USE_LEAVE + and there is exactly one register to pop. This heruistic may need some + tuning in future. */ + if ((!sp_valid && frame.nregs <= 1) + || (TARGET_EPILOGUE_USING_MOVE + && use_fast_prologue_epilogue + && (frame.nregs > 1 || frame.to_allocate)) + || (frame_pointer_needed && !frame.nregs && frame.to_allocate) + || (frame_pointer_needed && TARGET_USE_LEAVE + && use_fast_prologue_epilogue && frame.nregs == 1) + || current_function_calls_eh_return) + { + /* Restore registers. We can use ebp or esp to address the memory + locations. If both are available, default to ebp, since offsets + are known to be small. Only exception is esp pointing directly to the + end of block of saved registers, where we may simplify addressing + mode. */ + + if (!frame_pointer_needed || (sp_valid && !frame.to_allocate)) + ix86_emit_restore_regs_using_mov (stack_pointer_rtx, + frame.to_allocate, style == 2); + else + ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, + offset, style == 2); - limit = frame_pointer_needed - ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; + /* eh_return epilogues need %ecx added to the stack pointer. */ + if (style == 2) + { + rtx tmp, sa = EH_RETURN_STACKADJ_RTX; - if (nregs > 1 || sp_valid) - { - if ( !sp_valid ) + if (frame_pointer_needed) + { + tmp = gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, sa); + tmp = plus_constant (tmp, UNITS_PER_WORD); + emit_insn (gen_rtx_SET (VOIDmode, sa, tmp)); + + tmp = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx); + emit_move_insn (hard_frame_pointer_rtx, tmp); + + emit_insn (gen_pro_epilogue_adjust_stack + (stack_pointer_rtx, sa, const0_rtx)); + } + else + { + tmp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, sa); + tmp = plus_constant (tmp, (frame.to_allocate + + frame.nregs * UNITS_PER_WORD)); + emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp)); + } + } + else if (!frame_pointer_needed) + emit_insn (gen_pro_epilogue_adjust_stack + (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (frame.to_allocate + + frame.nregs * UNITS_PER_WORD))); + /* If not an i386, mov & pop is faster than "leave". */ + else if (TARGET_USE_LEAVE || optimize_size || !use_fast_prologue_epilogue) + emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ()); + else { - xops[0] = adj_offsettable_operand (AT_BP (QImode), offset); - if (do_rtl) - emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0))); + emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx, + hard_frame_pointer_rtx, + const0_rtx)); + if (TARGET_64BIT) + emit_insn (gen_popdi1 (hard_frame_pointer_rtx)); else - output_asm_insn (AS2 (lea%L2,%0,%2), xops); + emit_insn (gen_popsi1 (hard_frame_pointer_rtx)); + } + } + else + { + /* First step is to deallocate the stack frame so that we can + pop the registers. */ + if (!sp_valid) + { + if (!frame_pointer_needed) + abort (); + emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx, + hard_frame_pointer_rtx, + GEN_INT (offset))); } + else if (frame.to_allocate) + emit_insn (gen_pro_epilogue_adjust_stack + (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (frame.to_allocate))); - for (regno = 0; regno < limit; regno++) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (ix86_save_reg (regno, false)) { - xops[0] = gen_rtx_REG (SImode, regno); - - if (do_rtl) - emit_insn (gen_pop (xops[0])); + if (TARGET_64BIT) + emit_insn (gen_popdi1 (gen_rtx_REG (Pmode, regno))); else - output_asm_insn ("pop%L0 %0", xops); + emit_insn (gen_popsi1 (gen_rtx_REG (Pmode, regno))); } + if (frame_pointer_needed) + { + /* Leave results in shorter dependency chains on CPUs that are + able to grok it fast. */ + if (TARGET_USE_LEAVE) + emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ()); + else if (TARGET_64BIT) + emit_insn (gen_popdi1 (hard_frame_pointer_rtx)); + else + emit_insn (gen_popsi1 (hard_frame_pointer_rtx)); + } } - else - for (regno = 0; regno < limit; regno++) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + /* Sibcall epilogues don't want a return instruction. */ + if (style == 0) + return; + + if (current_function_pops_args && current_function_args_size) + { + rtx popc = GEN_INT (current_function_pops_args); + + /* i386 can only pop 64K bytes. If asked to pop more, pop + return address, do explicit add, and jump indirectly to the + caller. */ + + if (current_function_pops_args >= 65536) { - xops[0] = gen_rtx_REG (SImode, regno); - xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset); + rtx ecx = gen_rtx_REG (SImode, 2); - if (do_rtl) - emit_move_insn (xops[0], xops[1]); - else - output_asm_insn (AS2 (mov%L0,%1,%0), xops); + /* There are is no "pascal" calling convention in 64bit ABI. */ + if (TARGET_64BIT) + abort (); - offset += 4; + emit_insn (gen_popsi1 (ecx)); + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc)); + emit_jump_insn (gen_return_indirect_internal (ecx)); } + else + emit_jump_insn (gen_return_pop_internal (popc)); + } + else + emit_jump_insn (gen_return_internal ()); +} + +/* Extract the parts of an RTL expression that is a valid memory address + for an instruction. Return 0 if the structure of the address is + grossly off. Return -1 if the address contains ASHIFT, so it is not + strictly valid, but still used for computing length of lea instruction. + */ - if (frame_pointer_needed) +static int +ix86_decompose_address (addr, out) + register rtx addr; + struct ix86_address *out; +{ + rtx base = NULL_RTX; + rtx index = NULL_RTX; + rtx disp = NULL_RTX; + HOST_WIDE_INT scale = 1; + rtx scale_rtx = NULL_RTX; + int retval = 1; + + if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG) + base = addr; + else if (GET_CODE (addr) == PLUS) { - /* If not an i386, mov & pop is faster than "leave". */ + 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 (TARGET_USE_LEAVE) + if (code0 == REG || code0 == SUBREG) { - if (do_rtl) - emit_insn (gen_leave()); + if (code1 == REG || code1 == SUBREG) + index = op0, base = op1; /* index + base */ else - output_asm_insn ("leave", xops); + base = op0, disp = op1; /* base + displacement */ } - else + else if (code0 == MULT) { - 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])); - } + index = XEXP (op0, 0); + scale_rtx = XEXP (op0, 1); + if (code1 == REG || code1 == SUBREG) + base = op1; /* index*scale + base */ else - { - output_asm_insn (AS2 (mov%L2,%0,%2), xops); - output_asm_insn ("pop%L0 %0", xops); - } + disp = op1; /* index*scale + disp */ } - } - - 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) + else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) { - 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)); + index = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */ + scale_rtx = XEXP (XEXP (op0, 0), 1); + base = XEXP (op0, 1); + disp = op1; } - - if (use_pop) + else if (code0 == PLUS) { - 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); - } + index = XEXP (op0, 0); /* index + base + disp */ + base = XEXP (op0, 1); + disp = op1; } else - { - /* If there is no frame pointer, we must still release the frame. */ - xops[0] = GEN_INT (tsize); + return 0; + } + else if (GET_CODE (addr) == MULT) + { + index = XEXP (addr, 0); /* index*scale */ + scale_rtx = XEXP (addr, 1); + } + else if (GET_CODE (addr) == ASHIFT) + { + rtx tmp; - 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); - } + /* We're called for lea too, which implements ashift on occasion. */ + index = XEXP (addr, 0); + tmp = XEXP (addr, 1); + if (GET_CODE (tmp) != CONST_INT) + return 0; + scale = INTVAL (tmp); + if ((unsigned HOST_WIDE_INT) scale > 3) + return 0; + scale = 1 << scale; + retval = -1; } + else + disp = addr; /* displacement */ -#ifdef FUNCTION_BLOCK_PROFILER_EXIT - if (profile_block_flag == 2) + /* Extract the integral value of scale. */ + if (scale_rtx) { - FUNCTION_BLOCK_PROFILER_EXIT(file); + if (GET_CODE (scale_rtx) != CONST_INT) + return 0; + scale = INTVAL (scale_rtx); } -#endif - if (current_function_pops_args && current_function_args_size) + /* Allow arg pointer and stack pointer as index if there is not scaling */ + if (base && index && scale == 1 + && (index == arg_pointer_rtx || index == frame_pointer_rtx + || index == stack_pointer_rtx)) { - xops[1] = GEN_INT (current_function_pops_args); + rtx tmp = base; + base = index; + index = tmp; + } - /* 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. */ + /* Special case: %ebp cannot be encoded as a base without a displacement. */ + if ((base == hard_frame_pointer_rtx + || base == frame_pointer_rtx + || base == arg_pointer_rtx) && !disp) + disp = const0_rtx; - if (current_function_pops_args >= 32768) - { - /* ??? Which register to use here? */ - xops[0] = gen_rtx_REG (SImode, 2); + /* Special case: on K6, [%esi] makes the instruction vector decoded. + Avoid this by transforming to [%esi+0]. */ + if (ix86_cpu == PROCESSOR_K6 && !optimize_size + && base && !index && !disp + && REG_P (base) + && REGNO_REG_CLASS (REGNO (base)) == SIREG) + disp = const0_rtx; - 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); - } + /* Special case: encode reg+reg instead of reg*2. */ + if (!base && index && scale && scale == 2) + base = index, scale = 1; + + /* Special case: scaling cannot be encoded without base or displacement. */ + if (!base && !disp && index && scale != 1) + disp = const0_rtx; + + out->base = base; + out->index = index; + out->disp = disp; + out->scale = scale; + + return retval; } -/* 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. +/* Return cost of the memory address x. + 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. */ +int +ix86_address_cost (x) + rtx x; +{ + struct ix86_address parts; + int cost = 1; - It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should - convert common non-canonical forms to canonical form so that they will - be recognized. */ + if (!ix86_decompose_address (x, &parts)) + abort (); -#define ADDR_INVALID(msg,insn) \ -do { \ - if (TARGET_DEBUG_ADDR) \ - { \ - fprintf (stderr, msg); \ - debug_rtx (insn); \ - } \ -} while (0) + /* More complex memory references are better. */ + if (parts.disp && parts.disp != const0_rtx) + cost--; + + /* Attempt to minimize number of registers in the address. */ + if ((parts.base + && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER)) + || (parts.index + && (!REG_P (parts.index) + || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER))) + cost++; + + if (parts.base + && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER) + && parts.index + && (!REG_P (parts.index) || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER) + && parts.base != parts.index) + cost++; + + /* AMD-K6 don't like addresses with ModR/M set to 00_xxx_100b, + since it's predecode logic can't detect the length of instructions + and it degenerates to vector decoded. Increase cost of such + addresses here. The penalty is minimally 2 cycles. It may be worthwhile + to split such addresses or even refuse such addresses at all. + + Following addressing modes are affected: + [base+scale*index] + [scale*index+disp] + [base+index] + + The first and last case may be avoidable by explicitly coding the zero in + memory address, but I don't have AMD-K6 machine handy to check this + theory. */ + + if (TARGET_K6 + && ((!parts.disp && parts.base && parts.index && parts.scale != 1) + || (parts.disp && !parts.base && parts.index && parts.scale != 1) + || (!parts.disp && parts.base && parts.index && parts.scale == 1))) + cost += 10; + + return cost; +} + +/* If X is a machine specific address (i.e. a symbol or label being + referenced as a displacement from the GOT implemented using an + UNSPEC), then return the base term. Otherwise return X. */ + +rtx +ix86_find_base_term (x) + rtx x; +{ + rtx term; + + if (TARGET_64BIT) + { + if (GET_CODE (x) != CONST) + return x; + term = XEXP (x, 0); + if (GET_CODE (term) == PLUS + && (GET_CODE (XEXP (term, 1)) == CONST_INT + || GET_CODE (XEXP (term, 1)) == CONST_DOUBLE)) + term = XEXP (term, 0); + if (GET_CODE (term) != UNSPEC + || XVECLEN (term, 0) != 1 + || XINT (term, 1) != 15) + return x; + + term = XVECEXP (term, 0, 0); + + if (GET_CODE (term) != SYMBOL_REF + && GET_CODE (term) != LABEL_REF) + return x; + + return term; + } + + if (GET_CODE (x) != PLUS + || XEXP (x, 0) != pic_offset_table_rtx + || GET_CODE (XEXP (x, 1)) != CONST) + return x; + + term = XEXP (XEXP (x, 1), 0); + + if (GET_CODE (term) == PLUS && GET_CODE (XEXP (term, 1)) == CONST_INT) + term = XEXP (term, 0); + + if (GET_CODE (term) != UNSPEC + || XVECLEN (term, 0) != 1 + || XINT (term, 1) != 7) + return x; + + term = XVECEXP (term, 0, 0); + + if (GET_CODE (term) != SYMBOL_REF + && GET_CODE (term) != LABEL_REF) + return x; + + return term; +} + +/* Determine if a given CONST RTX is a valid memory displacement + in PIC mode. */ int legitimate_pic_address_disp_p (disp) register rtx disp; { + /* In 64bit mode we can allow direct addresses of symbols and labels + when they are not dynamic symbols. */ + if (TARGET_64BIT) + { + rtx x = disp; + if (GET_CODE (disp) == CONST) + x = XEXP (disp, 0); + /* ??? Handle PIC code models */ + if (GET_CODE (x) == PLUS + && (GET_CODE (XEXP (x, 1)) == CONST_INT + && ix86_cmodel == CM_SMALL_PIC + && INTVAL (XEXP (x, 1)) < 1024*1024*1024 + && INTVAL (XEXP (x, 1)) > -1024*1024*1024)) + x = XEXP (x, 0); + if (local_symbolic_operand (x, Pmode)) + return 1; + } if (GET_CODE (disp) != CONST) return 0; disp = XEXP (disp, 0); + if (TARGET_64BIT) + { + /* We are unsafe to allow PLUS expressions. This limit allowed distance + of GOT tables. We should not need these anyway. */ + if (GET_CODE (disp) != UNSPEC + || XVECLEN (disp, 0) != 1 + || XINT (disp, 1) != 15) + return 0; + + if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF + && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF) + return 0; + return 1; + } + if (GET_CODE (disp) == PLUS) { if (GET_CODE (XEXP (disp, 1)) != CONST_INT) @@ -2318,115 +4655,58 @@ legitimate_pic_address_disp_p (disp) 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; + switch (XINT (disp, 1)) + { + case 6: /* @GOT */ + return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF; - return 1; + case 7: /* @GOTOFF */ + return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode); + } + + return 0; } +/* 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. + + It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should + convert common non-canonical forms to canonical form so that they will + be recognized. */ + 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; + struct ix86_address parts; + rtx base, index, disp; + HOST_WIDE_INT scale; + const char *reason = NULL; + rtx reason_rtx = 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) + if (ix86_decompose_address (addr, &parts) <= 0) { - 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; - } + reason = "decomposition failed"; + goto report_error; } - else if (GET_CODE (addr) == MULT) - { - indx = XEXP (addr, 0); /* index*scale */ - scale = XEXP (addr, 1); - } + base = parts.base; + index = parts.index; + disp = parts.disp; + scale = parts.scale; - 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: + /* 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 @@ -2434,125 +4714,174 @@ legitimate_address_p (mode, addr, strict) if (base) { + reason_rtx = base; + if (GET_CODE (base) != REG) { - ADDR_INVALID ("Base is not a register.\n", base); - return FALSE; + reason = "base is not a register"; + goto report_error; } if (GET_MODE (base) != Pmode) { - ADDR_INVALID ("Base is not in Pmode.\n", base); - return FALSE; + reason = "base is not in Pmode"; + goto report_error; } 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; + reason = "base is not valid"; + goto report_error; } } - /* Validate index register: + /* 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 (index) { - if (GET_CODE (indx) != REG) + reason_rtx = index; + + if (GET_CODE (index) != REG) { - ADDR_INVALID ("Index is not a register.\n", indx); - return FALSE; + reason = "index is not a register"; + goto report_error; } - if (GET_MODE (indx) != Pmode) + if (GET_MODE (index) != Pmode) { - ADDR_INVALID ("Index is not in Pmode.\n", indx); - return FALSE; + reason = "index is not in Pmode"; + goto report_error; } - if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx)) - || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx))) + if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (index)) + || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (index))) { - ADDR_INVALID ("Index is not valid.\n", indx); - return FALSE; + reason = "index is not valid"; + goto report_error; } } - else if (scale) - abort (); /* scale w/o index invalid */ - /* Validate scale factor: */ - if (scale) + /* Validate scale factor. */ + if (scale != 1) { - HOST_WIDE_INT value; - - if (GET_CODE (scale) != CONST_INT) + reason_rtx = GEN_INT (scale); + if (!index) { - ADDR_INVALID ("Scale is not valid.\n", scale); - return FALSE; + reason = "scale without index"; + goto report_error; } - value = INTVAL (scale); - if (value != 1 && value != 2 && value != 4 && value != 8) + if (scale != 2 && scale != 4 && scale != 8) { - ADDR_INVALID ("Scale is not a good multiplier.\n", scale); - return FALSE; + reason = "scale is not a valid multiplier"; + goto report_error; } } /* Validate displacement. */ if (disp) { + reason_rtx = disp; + if (!CONSTANT_ADDRESS_P (disp)) { - ADDR_INVALID ("Displacement is not valid.\n", disp); - return FALSE; + reason = "displacement is not constant"; + goto report_error; } - else if (GET_CODE (disp) == CONST_DOUBLE) + if (TARGET_64BIT) + { + if (!x86_64_sign_extended_value (disp)) + { + reason = "displacement is out of range"; + goto report_error; + } + } + else { - ADDR_INVALID ("Displacement is a const_double.\n", disp); - return FALSE; + if (GET_CODE (disp) == CONST_DOUBLE) + { + reason = "displacement is a const_double"; + goto report_error; + } } if (flag_pic && SYMBOLIC_CONST (disp)) { - if (! legitimate_pic_address_disp_p (disp)) + if (TARGET_64BIT && (index || base)) { - ADDR_INVALID ("Displacement is an invalid PIC construct.\n", - disp); - return FALSE; + reason = "non-constant pic memory reference"; + goto report_error; } - - if (base != pic_offset_table_rtx - && (indx != pic_offset_table_rtx || scale != NULL_RTX)) + if (! legitimate_pic_address_disp_p (disp)) { - ADDR_INVALID ("PIC displacement against invalid base.\n", disp); - return FALSE; + reason = "displacement is an invalid pic construct"; + goto report_error; } - } + /* This code used to verify that a symbolic pic displacement + includes the pic_offset_table_rtx register. + + While this is good idea, unfortunately these constructs may + be created by "adds using lea" optimization for incorrect + code like: + + int a; + int foo(int i) + { + return *(&a+i); + } + + This code is nonsensical, but results in addressing + GOT table with pic_offset_table_rtx base. We can't + just refuse it easily, since it gets matched by + "addsi3" pattern, that later gets split to lea in the + case output register differs from input. While this + can be handled by separate addsi pattern for this case + that never results in lea, this seems to be easier and + correct fix for crash to disable this test. */ + } else if (HALF_PIC_P ()) { if (! HALF_PIC_ADDRESS_P (disp) - || (base != NULL_RTX || indx != NULL_RTX)) + || (base != NULL_RTX || index != NULL_RTX)) { - ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", - disp); - return FALSE; + reason = "displacement is an invalid half-pic reference"; + goto report_error; } } } + /* Everything looks valid. */ if (TARGET_DEBUG_ADDR) - fprintf (stderr, "Address is valid.\n"); - - /* Everything looks valid, return true */ + fprintf (stderr, "Success.\n"); return TRUE; + +report_error: + if (TARGET_DEBUG_ADDR) + { + fprintf (stderr, "Error: %s\n", reason); + debug_rtx (reason_rtx); + } + return FALSE; } +/* Return an unique alias set for the GOT. */ + +static HOST_WIDE_INT +ix86_GOT_alias_set () +{ + static HOST_WIDE_INT set = -1; + if (set == -1) + set = new_alias_set (); + return set; +} + /* Return a legitimate reference for ORIG (an address) using the register REG. If REG is 0, a new pseudo is generated. @@ -2580,42 +4909,66 @@ legitimize_pic_address (orig, reg) 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)))) + if (local_symbolic_operand (addr, Pmode)) { - /* This symbol may be referenced via a displacement from the PIC - base address (@GOTOFF). */ + /* In 64bit mode we can address such objects directly. */ + if (TARGET_64BIT) + new = addr; + else + { + /* 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); + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 7); + new = gen_rtx_CONST (Pmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); - if (reg != 0) + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + } + else if (GET_CODE (addr) == SYMBOL_REF) + { + if (TARGET_64BIT) { + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 15); + new = gen_rtx_CONST (Pmode, new); + new = gen_rtx_MEM (Pmode, new); + RTX_UNCHANGING_P (new) = 1; + set_mem_alias_set (new, ix86_GOT_alias_set ()); + + if (reg == 0) + reg = gen_reg_rtx (Pmode); + /* Use directly gen_movsi, otherwise the address is loaded + into register for CSE. We don't want to CSE this addresses, + instead we CSE addresses from the GOT table, so skip this. */ + emit_insn (gen_movsi (reg, new)); + new = reg; + } + else + { + /* 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 (Pmode, gen_rtvec (1, addr), 6); + new = gen_rtx_CONST (Pmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + new = gen_rtx_MEM (Pmode, new); + RTX_UNCHANGING_P (new) = 1; + set_mem_alias_set (new, ix86_GOT_alias_set ()); + + if (reg == 0) + reg = gen_reg_rtx (Pmode); 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) @@ -2626,7 +4979,7 @@ legitimize_pic_address (orig, reg) /* Check that the unspec is one of the ones we generate? */ } else if (GET_CODE (addr) != PLUS) - abort(); + abort (); } if (GET_CODE (addr) == PLUS) { @@ -2634,22 +4987,26 @@ legitimize_pic_address (orig, reg) /* 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)))) + if (local_symbolic_operand (op0, Pmode) && 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 (!TARGET_64BIT) + { + current_function_uses_pic_offset_table = 1; + new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 7); + new = gen_rtx_PLUS (Pmode, new, op1); + new = gen_rtx_CONST (Pmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); - if (reg != 0) + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + else { - emit_move_insn (reg, new); - new = reg; + /* ??? We need to limit offsets here. */ } } else @@ -2675,21 +5032,6 @@ legitimize_pic_address (orig, reg) 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. @@ -2733,7 +5075,7 @@ legitimize_address (x, oldx, mode) /* 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) + && (log = (unsigned) exact_log2 (INTVAL (XEXP (x, 1)))) < 4) { changed = 1; x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)), @@ -2742,29 +5084,29 @@ legitimize_address (x, oldx, mode) if (GET_CODE (x) == PLUS) { - /* Canonicalize shifts by 0, 1, 2, 3 into multiply. */ + /* 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) + && (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)); + 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) + && (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)); + 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. */ + /* Put multiply first if it isn't already. */ if (GET_CODE (XEXP (x, 1)) == MULT) { rtx tmp = XEXP (x, 0); @@ -2780,10 +5122,10 @@ legitimize_address (x, oldx, mode) 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)); + x = gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (Pmode, XEXP (x, 0), + XEXP (XEXP (x, 1), 0)), + XEXP (XEXP (x, 1), 1)); } /* Canonicalize @@ -2813,10 +5155,10 @@ legitimize_address (x, oldx, mode) 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))); + 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))); } } @@ -2943,13 +5285,13 @@ output_pic_addr_const (file, x, code) if (GET_CODE (XEXP (x, 0)) == CONST_INT) { output_pic_addr_const (file, XEXP (x, 0), code); - fprintf (file, "+"); + putc ('+', 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, "+"); + putc ('+', file); output_pic_addr_const (file, XEXP (x, 0), code); } else @@ -2957,254 +5299,280 @@ output_pic_addr_const (file, x, code) break; case MINUS: + putc (ASSEMBLER_DIALECT == ASM_INTEL ? '(' : '[', file); output_pic_addr_const (file, XEXP (x, 0), code); - fprintf (file, "-"); + putc ('-', file); output_pic_addr_const (file, XEXP (x, 1), code); + putc (ASSEMBLER_DIALECT == ASM_INTEL ? ')' : ']', file); break; case UNSPEC: if (XVECLEN (x, 0) != 1) - abort (); + 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; - } + { + case 6: + fputs ("@GOT", file); + break; + case 7: + fputs ("@GOTOFF", file); + break; + case 8: + fputs ("@PLT", file); + break; + case 15: + fputs ("@GOTPCREL(%RIP)", file); + break; + default: + output_operand_lossage ("invalid UNSPEC as operand"); + break; + } break; default: output_operand_lossage ("invalid expression as operand"); } } + +/* This is called from dwarfout.c via ASM_OUTPUT_DWARF_ADDR_CONST. + We need to handle our special PIC relocations. */ + +void +i386_dwarf_output_addr_const (file, x) + FILE *file; + rtx x; +{ +#ifdef ASM_QUAD + fprintf (file, "%s", TARGET_64BIT ? ASM_QUAD : ASM_LONG); +#else + if (TARGET_64BIT) + abort (); + fprintf (file, "%s", ASM_LONG); +#endif + if (flag_pic) + output_pic_addr_const (file, x, '\0'); + else + output_addr_const (file, x); + fputc ('\n', file); +} + +/* In the name of slightly smaller debug output, and to cater to + general assembler losage, recognize PIC+GOTOFF and turn it back + into a direct symbol reference. */ + +rtx +i386_simplify_dwarf_addr (orig_x) + rtx orig_x; +{ + rtx x = orig_x; + + if (TARGET_64BIT) + { + if (GET_CODE (x) != CONST + || GET_CODE (XEXP (x, 0)) != UNSPEC + || XINT (XEXP (x, 0), 1) != 15) + return orig_x; + return XVECEXP (XEXP (x, 0), 0, 0); + } + + if (GET_CODE (x) != PLUS + || GET_CODE (XEXP (x, 0)) != REG + || GET_CODE (XEXP (x, 1)) != CONST) + return orig_x; + + x = XEXP (XEXP (x, 1), 0); + if (GET_CODE (x) == UNSPEC + && (XINT (x, 1) == 6 + || XINT (x, 1) == 7)) + return XVECEXP (x, 0, 0); + + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 0)) == UNSPEC + && GET_CODE (XEXP (x, 1)) == CONST_INT + && (XINT (XEXP (x, 0), 1) == 6 + || XINT (XEXP (x, 0), 1) == 7)) + return gen_rtx_PLUS (VOIDmode, XVECEXP (XEXP (x, 0), 0, 0), XEXP (x, 1)); + + return orig_x; +} static void -put_jump_code (code, reverse, file) +put_condition_code (code, mode, reverse, fp, file) enum rtx_code code; - int reverse; + enum machine_mode mode; + int reverse, fp; FILE *file; { - int flags = cc_prev_status.flags; - int ieee = (TARGET_IEEE_FP && (flags & CC_IN_80387) - && !(cc_prev_status.flags & CC_FCOMI)); 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) + if (mode == CCFPmode || mode == CCFPUmode) { - 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; + enum rtx_code second_code, bypass_code; + ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code); + if (bypass_code != NIL || second_code != NIL) + abort (); + code = ix86_fp_compare_code_to_integer (code); + mode = CCmode; } - 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"; + if (mode != CCmode && mode != CCNOmode && mode != CCGCmode) + abort (); + suffix = "g"; break; - case GTU: - suffix = "a"; + /* ??? Use "nbe" instead of "a" for fcmov losage on some assemblers. + Those same assemblers have the same but opposite losage on cmov. */ + if (mode != CCmode) + abort (); + suffix = fp ? "nbe" : "a"; break; - case LT: - if (flags & CC_NO_OVERFLOW) + if (mode == CCNOmode || mode == CCGOCmode) suffix = "s"; + else if (mode == CCmode || mode == CCGCmode) + suffix = "l"; else - suffix = flags & CC_IN_80387 ? "b" : "l"; + abort (); break; - case LTU: + if (mode != CCmode) + abort (); suffix = "b"; break; - case GE: - if (flags & CC_NO_OVERFLOW) + if (mode == CCNOmode || mode == CCGOCmode) suffix = "ns"; + else if (mode == CCmode || mode == CCGCmode) + suffix = "ge"; else - suffix = flags & CC_IN_80387 ? "ae" : "ge"; + abort (); break; - case GEU: - suffix = "ae"; + /* ??? As above. */ + if (mode != CCmode) + abort (); + suffix = fp ? "nb" : "ae"; break; - case LE: - suffix = flags & CC_IN_80387 ? "be" : "le"; + if (mode != CCmode && mode != CCGCmode && mode != CCNOmode) + abort (); + suffix = "le"; break; - case LEU: + if (mode != CCmode) + abort (); suffix = "be"; break; - + case UNORDERED: + suffix = fp ? "u" : "p"; + break; + case ORDERED: + suffix = fp ? "nu" : "np"; + 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; +void +print_reg (x, code, file) + rtx x; + int code; + 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; + if (REGNO (x) == ARG_POINTER_REGNUM + || REGNO (x) == FRAME_POINTER_REGNUM + || REGNO (x) == FLAGS_REG + || REGNO (x) == FPSR_REG) + abort (); - default: - output_operand_lossage ("Invalid %%C operand"); - } + if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0) + putc ('%', file); + + if (code == 'w' || MMX_REG_P (x)) + code = 2; + else if (code == 'b') + code = 1; + else if (code == 'k') + code = 4; + else if (code == 'q') + code = 8; + else if (code == 'y') + code = 3; + else if (code == 'h') + code = 0; + else + code = GET_MODE_SIZE (GET_MODE (x)); - 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"); + /* Irritatingly, AMD extended registers use different naming convention + from the normal registers. */ + if (REX_INT_REG_P (x)) + { + if (!TARGET_64BIT) + abort (); + switch (code) + { + case 0: + error ("extended registers have no high halves"); + break; + case 1: + fprintf (file, "r%ib", REGNO (x) - FIRST_REX_INT_REG + 8); + break; + case 2: + fprintf (file, "r%iw", REGNO (x) - FIRST_REX_INT_REG + 8); + break; + case 4: + fprintf (file, "r%id", REGNO (x) - FIRST_REX_INT_REG + 8); + break; + case 8: + fprintf (file, "r%i", REGNO (x) - FIRST_REX_INT_REG + 8); + break; + default: + error ("unsupported operand size for extended register"); + break; + } + return; + } + switch (code) + { + case 3: + if (STACK_TOP_P (x)) + { + fputs ("st(0)", file); + break; + } + /* FALLTHRU */ + case 8: + case 4: + case 12: + if (! ANY_FP_REG_P (x)) + putc (code == 8 && TARGET_64BIT ? 'r' : 'e', file); + /* FALLTHRU */ + case 16: + 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; + default: + abort (); } } @@ -3212,25 +5580,25 @@ put_condition_code (code, reverse_cc, mode, file) 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 + F,f -- likewise, but for floating-point. 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) + A -- print an absolute memory reference. 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 */ + q -- likewise, print the DImode 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. + D -- print condition for SSE cmp instruction. + P -- if PIC, print an @PLT suffix. + X -- don't print any sort of PIC '@' suffix for a symbol. + */ void print_operand (file, x, code) @@ -3243,43 +5611,65 @@ print_operand (file, x, code) switch (code) { case '*': - if (USE_STAR) + if (ASSEMBLER_DIALECT == ASM_ATT) putc ('*', file); return; - case '_': -#ifdef YES_UNDERSCORES - putc ('_', file); -#endif + case 'A': + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('*', file); + else if (ASSEMBLER_DIALECT == ASM_INTEL) + { + /* Intel syntax. For absolute addresses, registers should not + be surrounded by braces. */ + if (GET_CODE (x) != REG) + { + putc ('[', file); + PRINT_OPERAND (file, x, 0); + putc (']', file); + return; + } + } + else + abort (); + + PRINT_OPERAND (file, x, 0); return; + case 'L': - PUT_OP_SIZE (code, 'l', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('l', file); return; case 'W': - PUT_OP_SIZE (code, 'w', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('w', file); return; case 'B': - PUT_OP_SIZE (code, 'b', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('b', file); return; case 'Q': - PUT_OP_SIZE (code, 'l', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('l', file); return; case 'S': - PUT_OP_SIZE (code, 's', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('s', file); return; case 'T': - PUT_OP_SIZE (code, 't', file); + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('t', file); return; case 'z': /* 387 opcodes don't get size suffixes if the operands are - registers. */ + registers. */ if (STACK_REG_P (x)) return; @@ -3289,36 +5679,37 @@ print_operand (file, x, code) { case 2: #ifdef HAVE_GAS_FILDS_FISTS - PUT_OP_SIZE ('W', 's', file); + putc ('s', file); #endif return; case 4: if (GET_MODE (x) == SFmode) { - PUT_OP_SIZE ('S', 's', file); + putc ('s', file); return; } else - PUT_OP_SIZE ('L', 'l', file); + putc ('l', file); return; case 12: - PUT_OP_SIZE ('T', 't', file); - return; + case 16: + putc ('t', file); + return; case 8: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) { #ifdef GAS_MNEMONICS - PUT_OP_SIZE ('Q', 'q', file); - return; + putc ('q', file); #else - PUT_OP_SIZE ('Q', 'l', file); /* Fall through */ + putc ('l', file); + putc ('l', file); #endif } - - PUT_OP_SIZE ('Q', 'l', file); + else + putc ('l', file); return; default: @@ -3328,73 +5719,119 @@ print_operand (file, x, code) case 'b': case 'w': case 'k': + case 'q': case 'h': case 'y': - case 'P': case 'X': + case 'P': 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); + putc (',', file); } - return; case 'D': - put_jump_code (GET_CODE (x), 0, file); - return; - - case 'd': - put_jump_code (GET_CODE (x), 1, file); + /* Little bit of braindamage here. The SSE compare instructions + does use completely different names for the comparisons that the + fp conditional moves. */ + switch (GET_CODE (x)) + { + case EQ: + case UNEQ: + fputs ("eq", file); + break; + case LT: + case UNLT: + fputs ("lt", file); + break; + case LE: + case UNLE: + fputs ("le", file); + break; + case UNORDERED: + fputs ("unord", file); + break; + case NE: + case LTGT: + fputs ("neq", file); + break; + case UNGE: + case GE: + fputs ("nlt", file); + break; + case UNGT: + case GT: + fputs ("nle", file); + break; + case ORDERED: + fputs ("ord", file); + break; + default: + abort (); + break; + } return; - - /* This is used by the conditional move instructions. */ case 'C': - put_condition_code (GET_CODE (x), 0, MODE_INT, file); + put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 0, 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); + put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 1, file); return; /* Like above, but reverse condition */ + case 'c': + /* Check to see if argument to %c is really a constant + and not a condition code which needs to be reversed. */ + if (GET_RTX_CLASS (GET_CODE (x)) != '<') + { + output_operand_lossage ("operand is neither a constant nor a condition code, invalid operand code 'c'"); + return; + } + put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 0, file); + return; case 'f': - put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file); + put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file); return; + case '+': + { + rtx x; + if (!optimize || optimize_size || !TARGET_BRANCH_PREDICTION_HINTS) + return; + + x = find_reg_note (current_output_insn, REG_BR_PROB, 0); + if (x) + { + int pred_val = INTVAL (XEXP (x, 0)); + + if (pred_val < REG_BR_PROB_BASE * 45 / 100 + || pred_val > REG_BR_PROB_BASE * 55 / 100) + { + int taken = pred_val > REG_BR_PROB_BASE / 2; + int cputaken = final_forward_branch_p (current_output_insn) == 0; + + /* Emit hints only in the case default branch prediction + heruistics would fail. */ + if (taken != cputaken) + { + /* We use 3e (DS) prefix for taken branches and + 2e (CS) prefix for not taken branches. */ + if (taken) + fputs ("ds ; ", file); + else + fputs ("cs ; ", file); + } + } + } + return; + } default: { char str[50]; - sprintf (str, "invalid operand code `%c'", code); output_operand_lossage (str); } @@ -3408,16 +5845,43 @@ print_operand (file, x, code) else if (GET_CODE (x) == MEM) { - PRINT_PTR (x, file); - if (CONSTANT_ADDRESS_P (XEXP (x, 0))) + /* No `byte ptr' prefix for call instructions. */ + if (ASSEMBLER_DIALECT == ASM_INTEL && code != 'X' && code != 'P') { - if (flag_pic) - output_pic_addr_const (file, XEXP (x, 0), code); - else - output_addr_const (file, XEXP (x, 0)); + const char * size; + switch (GET_MODE_SIZE (GET_MODE (x))) + { + case 1: size = "BYTE"; break; + case 2: size = "WORD"; break; + case 4: size = "DWORD"; break; + case 8: size = "QWORD"; break; + case 12: size = "XWORD"; break; + case 16: size = "XMMWORD"; break; + default: + abort (); + } + + /* Check for explicit size override (codes 'b', 'w' and 'k') */ + if (code == 'b') + size = "BYTE"; + else if (code == 'w') + size = "WORD"; + else if (code == 'k') + size = "DWORD"; + + fputs (size, file); + fputs (" PTR ", file); } + + x = XEXP (x, 0); + if (flag_pic && CONSTANT_ADDRESS_P (x)) + output_pic_addr_const (file, x, code); + /* Avoid (%rip) for call operands. */ + else if (CONSTANT_ADDRESS_P (x) && code =='P' + && GET_CODE (x) != CONST_INT) + output_addr_const (file, x); else - output_address (XEXP (x, 0)); + output_address (x); } else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) @@ -3427,11 +5891,13 @@ print_operand (file, x, code) REAL_VALUE_FROM_CONST_DOUBLE (r, x); REAL_VALUE_TO_TARGET_SINGLE (r, l); - PRINT_IMMED_PREFIX (file); + + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('$', file); fprintf (file, "0x%lx", l); } - /* These float cases don't actually occur as immediate operands. */ + /* 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; @@ -3442,7 +5908,8 @@ print_operand (file, x, code) fprintf (file, "%s", dstr); } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) + else if (GET_CODE (x) == CONST_DOUBLE + && (GET_MODE (x) == XFmode || GET_MODE (x) == TFmode)) { REAL_VALUE_TYPE r; char dstr[30]; @@ -3456,12 +5923,22 @@ print_operand (file, x, code) if (code != 'P') { if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) - PRINT_IMMED_PREFIX (file); + { + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('$', file); + } else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) - PRINT_OFFSET_PREFIX (file); + { + if (ASSEMBLER_DIALECT == ASM_ATT) + putc ('$', file); + else + fputs ("OFFSET FLAT:", file); + } } - if (flag_pic) + if (GET_CODE (x) == CONST_INT) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + else if (flag_pic) output_pic_addr_const (file, x, code); else output_addr_const (file, x); @@ -3475,317 +5952,163 @@ 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; + struct ix86_address parts; + rtx base, index, disp; + int scale; - 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 (! ix86_decompose_address (addr, &parts)) + abort (); - 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; + base = parts.base; + index = parts.index; + disp = parts.disp; + scale = parts.scale; - addr = 0; - } - - if (offset != 0) - { - if (addr != 0) - abort (); - addr = offset; - } + if (!base && !index) + { + /* Displacement only requires special attention. */ - 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))) + if (GET_CODE (disp) == CONST_INT) { - breg = reg1; - ireg = reg2; + if (ASSEMBLER_DIALECT == ASM_INTEL) + { + if (USER_LABEL_PREFIX[0] == 0) + putc ('%', file); + fputs ("ds:", file); + } + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); } + else if (flag_pic) + output_pic_addr_const (file, addr, 0); + else + output_addr_const (file, addr); - if (ireg != 0 || breg != 0) + /* Use one byte shorter RIP relative addressing for 64bit mode. */ + if (GET_CODE (disp) != CONST_INT && TARGET_64BIT) + fputs ("(%rip)", file); + } + else + { + if (ASSEMBLER_DIALECT == ASM_ATT) { - int scale = 1; - - if (addr != 0) + if (disp) { if (flag_pic) - output_pic_addr_const (file, addr, 0); - else if (GET_CODE (addr) == LABEL_REF) - output_asm_label (addr); + output_pic_addr_const (file, disp, 0); + else if (GET_CODE (disp) == LABEL_REF) + output_asm_label (disp); else - output_addr_const (file, addr); + output_addr_const (file, disp); } - if (ireg != 0 && GET_CODE (ireg) == MULT) + putc ('(', file); + if (base) + PRINT_REG (base, 0, file); + if (index) { - scale = INTVAL (XEXP (ireg, 1)); - ireg = XEXP (ireg, 0); + putc (',', file); + PRINT_REG (index, 0, file); + if (scale != 1) + fprintf (file, ",%d", scale); } + putc (')', file); + } + else + { + rtx offset = NULL_RTX; - /* 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) + if (disp) { - rtx tmp; + /* Pull out the offset of a symbol; print any symbol itself. */ + if (GET_CODE (disp) == CONST + && GET_CODE (XEXP (disp, 0)) == PLUS + && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) + { + offset = XEXP (XEXP (disp, 0), 1); + disp = gen_rtx_CONST (VOIDmode, + XEXP (XEXP (disp, 0), 0)); + } - tmp = breg; - breg = ireg; - ireg = tmp; + if (flag_pic) + output_pic_addr_const (file, disp, 0); + else if (GET_CODE (disp) == LABEL_REF) + output_asm_label (disp); + else if (GET_CODE (disp) == CONST_INT) + offset = disp; + else + output_addr_const (file, disp); } - /* 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); + putc ('[', file); + if (base) + { + PRINT_REG (base, 0, file); + if (offset) + { + if (INTVAL (offset) >= 0) + putc ('+', file); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset)); + } + } + else if (offset) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset)); else - output_addr_const (file, addr); + putc ('0', file); + + if (index) + { + putc ('+', file); + PRINT_REG (index, 0, file); + if (scale != 1) + fprintf (file, "*%d", scale); + } + putc (']', file); } } } -/* 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. */ +/* 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 -notice_update_cc (exp) - rtx exp; +split_di (operands, num, lo_half, hi_half) + rtx operands[]; + int num; + rtx lo_half[], hi_half[]; { - if (GET_CODE (exp) == SET) + while (num--) { - /* 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; - } + rtx op = operands[num]; - /* Tests and compares set the cc's in predictable ways. */ - else if (SET_DEST (exp) == cc0_rtx) + /* simplify_subreg refuse to split volatile memory addresses, + but we still have to handle it. */ + if (GET_CODE (op) == MEM) { - CC_STATUS_INIT; - cc_status.value1 = SET_SRC (exp); - return; + lo_half[num] = adjust_address (op, SImode, 0); + hi_half[num] = adjust_address (op, SImode, 4); } - - /* 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; + lo_half[num] = simplify_gen_subreg (SImode, op, + GET_MODE (op) == VOIDmode + ? DImode : GET_MODE (op), 0); + hi_half[num] = simplify_gen_subreg (SImode, op, + GET_MODE (op) == VOIDmode + ? DImode : GET_MODE (op), 4); } } - 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 (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 +/* Split one or more TImode 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". */ + that parallel "operands". */ void -split_di (operands, num, lo_half, hi_half) +split_ti (operands, num, lo_half, hi_half) rtx operands[]; int num; rtx lo_half[], hi_half[]; @@ -3793,129 +6116,117 @@ split_di (operands, num, 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) + + /* simplify_subreg refuse to split volatile memory addresses, but we + still have to handle it. */ + if (GET_CODE (op) == MEM) { - lo_half[num] = gen_rtx_REG (SImode, REGNO (op)); - hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1); + lo_half[num] = adjust_address (op, DImode, 0); + hi_half[num] = adjust_address (op, DImode, 8); } - else if (CONSTANT_P (op)) - split_double (op, &lo_half[num], &hi_half[num]); - else if (offsettable_memref_p (op)) + else { - 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); + lo_half[num] = simplify_gen_subreg (DImode, op, TImode, 0); + hi_half[num] = simplify_gen_subreg (DImode, op, TImode, 8); } - 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. */ + might be within FLOAT or FLOAT_EXTEND expressions. */ + +#ifndef SYSV386_COMPAT +/* Set to 1 for compatibility with brain-damaged assemblers. No-one + wants to fix the assemblers because that causes incompatibility + with gcc. No-one wants to fix gcc because that causes + incompatibility with assemblers... You can use the option of + -DSYSV386_COMPAT=0 if you recompile both gcc and gas this way. */ +#define SYSV386_COMPAT 1 +#endif -char * +const char * output_387_binary_op (insn, operands) rtx insn; rtx *operands; { - rtx temp; - char *base_op; - static char buf[100]; + static char buf[30]; + const char *p; + const char *ssep; + int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]) | SSE_REG_P (operands[2]); + +#ifdef ENABLE_CHECKING + /* Even if we do not want to check the inputs, this documents input + constraints. Which helps in understanding the following code. */ + if (STACK_REG_P (operands[0]) + && ((REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1]) + && (STACK_REG_P (operands[2]) || GET_CODE (operands[2]) == MEM)) + || (REG_P (operands[2]) + && REGNO (operands[0]) == REGNO (operands[2]) + && (STACK_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM))) + && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2]))) + ; /* ok */ + else if (!is_sse) + abort (); +#endif switch (GET_CODE (operands[3])) { case PLUS: - base_op = "fadd"; + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) + p = "fiadd"; + else + p = "fadd"; + ssep = "add"; break; case MINUS: - base_op = "fsub"; + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) + p = "fisub"; + else + p = "fsub"; + ssep = "sub"; break; case MULT: - base_op = "fmul"; + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) + p = "fimul"; + else + p = "fmul"; + ssep = "mul"; break; case DIV: - base_op = "fdiv"; + if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) + p = "fidiv"; + else + p = "fdiv"; + ssep = "div"; break; default: abort (); } - strcpy (buf, base_op); + if (is_sse) + { + strcpy (buf, ssep); + if (GET_MODE (operands[0]) == SFmode) + strcat (buf, "ss\t{%2, %0|%0, %2}"); + else + strcat (buf, "sd\t{%2, %0|%0, %2}"); + return buf; + } + strcpy (buf, p); switch (GET_CODE (operands[3])) { @@ -3923,1819 +6234,6081 @@ output_387_binary_op (insn, operands) case PLUS: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) { - temp = operands[2]; + rtx temp = operands[2]; operands[2] = operands[1]; operands[1] = temp; } - if (GET_CODE (operands[2]) == MEM) - return strcat (buf, AS1 (%z2,%2)); + /* know operands[0] == operands[1]. */ - if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) - abort (); + if (GET_CODE (operands[2]) == MEM) + { + p = "%z2\t%2"; + break; + } if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) { if (STACK_TOP_P (operands[0])) - return strcat (buf, AS2 (p,%0,%2)); + /* How is it that we are storing to a dead operand[2]? + Well, presumably operands[1] is dead too. We can't + store the result to st(0) as st(0) gets popped on this + instruction. Instead store to operands[2] (which I + think has to be st(1)). st(1) will be popped later. + gcc <= 2.8.1 didn't have this check and generated + assembly code that the Unixware assembler rejected. */ + p = "p\t{%0, %2|%2, %0}"; /* st(1) = st(0) op st(1); pop */ else - return strcat (buf, AS2 (p,%2,%0)); + p = "p\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0); pop */ + break; } if (STACK_TOP_P (operands[0])) - return strcat (buf, AS2C (%y2,%0)); + p = "\t{%y2, %0|%0, %y2}"; /* st(0) = st(0) op st(r2) */ else - return strcat (buf, AS2C (%2,%0)); + p = "\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0) */ + break; case MINUS: case DIV: if (GET_CODE (operands[1]) == MEM) - return strcat (buf, AS1 (r%z1,%1)); + { + p = "r%z1\t%1"; + break; + } if (GET_CODE (operands[2]) == MEM) - return strcat (buf, AS1 (%z2,%2)); - - if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) - abort (); + { + p = "%z2\t%2"; + break; + } if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) { +#if SYSV386_COMPAT + /* The SystemV/386 SVR3.2 assembler, and probably all AT&T + derived assemblers, confusingly reverse the direction of + the operation for fsub{r} and fdiv{r} when the + destination register is not st(0). The Intel assembler + doesn't have this brain damage. Read !SYSV386_COMPAT to + figure out what the hardware really does. */ + if (STACK_TOP_P (operands[0])) + p = "{p\t%0, %2|rp\t%2, %0}"; + else + p = "{rp\t%2, %0|p\t%0, %2}"; +#else if (STACK_TOP_P (operands[0])) - return strcat (buf, AS2 (p,%0,%2)); + /* As above for fmul/fadd, we can't store to st(0). */ + p = "rp\t{%0, %2|%2, %0}"; /* st(1) = st(0) op st(1); pop */ else - return strcat (buf, AS2 (rp,%2,%0)); + p = "p\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0); pop */ +#endif + break; } if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) { +#if SYSV386_COMPAT + if (STACK_TOP_P (operands[0])) + p = "{rp\t%0, %1|p\t%1, %0}"; + else + p = "{p\t%1, %0|rp\t%0, %1}"; +#else if (STACK_TOP_P (operands[0])) - return strcat (buf, AS2 (rp,%0,%1)); + p = "p\t{%0, %1|%1, %0}"; /* st(1) = st(1) op st(0); pop */ else - return strcat (buf, AS2 (p,%1,%0)); + p = "rp\t{%1, %0|%0, %1}"; /* st(r2) = st(0) op st(r2); pop */ +#endif + break; } if (STACK_TOP_P (operands[0])) { if (STACK_TOP_P (operands[1])) - return strcat (buf, AS2C (%y2,%0)); + p = "\t{%y2, %0|%0, %y2}"; /* st(0) = st(0) op st(r2) */ else - return strcat (buf, AS2 (r,%y1,%0)); + p = "r\t{%y1, %0|%0, %y1}"; /* st(0) = st(r1) op st(0) */ + break; } else if (STACK_TOP_P (operands[1])) - return strcat (buf, AS2C (%1,%0)); + { +#if SYSV386_COMPAT + p = "{\t%1, %0|r\t%0, %1}"; +#else + p = "r\t{%1, %0|%0, %1}"; /* st(r2) = st(0) op st(r2) */ +#endif + } else - return strcat (buf, AS2 (r,%2,%0)); + { +#if SYSV386_COMPAT + p = "{r\t%2, %0|\t%0, %2}"; +#else + p = "\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0) */ +#endif + } + break; default: abort (); } + + strcat (buf, p); + return buf; } - + +/* Output code to initialize control word copies used by + trunc?f?i patterns. NORMAL is set to current control word, while ROUND_DOWN + is set to control word rounding downwards. */ +void +emit_i387_cw_initialization (normal, round_down) + rtx normal, round_down; +{ + rtx reg = gen_reg_rtx (HImode); + + emit_insn (gen_x86_fnstcw_1 (normal)); + emit_move_insn (reg, normal); + if (!TARGET_PARTIAL_REG_STALL && !optimize_size + && !TARGET_64BIT) + emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc))); + else + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0xc00))); + emit_move_insn (round_down, reg); +} + /* 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. */ + are the insn operands. The output may be [HSD]Imode and the input + operand may be [SDX]Fmode. */ -char * +const 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]; + int dimode_p = GET_MODE (operands[0]) == DImode; - if (! STACK_TOP_P (operands[1])) + /* Jump through a hoop or two for DImode, since the hardware has no + non-popping instruction. We used to do this a different way, but + that was somewhat fragile and broke with post-reload splitters. */ + if (dimode_p && !stack_top_dies) + output_asm_insn ("fld\t%y1", operands); + + if (!STACK_TOP_P (operands[1])) abort (); - if (GET_MODE (operands[0]) == DImode && ! stack_top_dies) + if (GET_CODE (operands[0]) != MEM) abort (); - xops[0] = GEN_INT (0x0c00); - xops[1] = operands[5]; + output_asm_insn ("fldcw\t%3", operands); + if (stack_top_dies || dimode_p) + output_asm_insn ("fistp%z0\t%0", operands); + else + output_asm_insn ("fist%z0\t%0", operands); + output_asm_insn ("fldcw\t%2", operands); - 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); + return ""; +} - xops[0] = NON_STACK_REG_P (operands[0]) ? operands[4] : operands[0]; +/* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi + should be used and 2 when fnstsw should be used. UNORDERED_P is true + when fucom should be used. */ - if (stack_top_dies) - output_asm_insn (AS1 (fistp%z0,%y0), xops); - else - output_asm_insn (AS1 (fist%z0,%y0), xops); +const char * +output_fp_compare (insn, operands, eflags_p, unordered_p) + rtx insn; + rtx *operands; + int eflags_p, unordered_p; +{ + int stack_top_dies; + rtx cmp_op0 = operands[0]; + rtx cmp_op1 = operands[1]; + int is_sse = SSE_REG_P (operands[0]) | SSE_REG_P (operands[1]); - if (NON_STACK_REG_P (operands[0])) + if (eflags_p == 2) + { + cmp_op0 = cmp_op1; + cmp_op1 = operands[2]; + } + if (is_sse) { - if (GET_MODE (operands[0]) == SImode) - output_asm_insn (AS2 (mov%L0,%4,%0), operands); + if (GET_MODE (operands[0]) == SFmode) + if (unordered_p) + return "ucomiss\t{%1, %0|%0, %1}"; + else + return "comiss\t{%1, %0|%0, %y}"; + else + if (unordered_p) + return "ucomisd\t{%1, %0|%0, %1}"; + else + return "comisd\t{%1, %0|%0, %y}"; + } + + if (! STACK_TOP_P (cmp_op0)) + abort (); + + stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (STACK_REG_P (cmp_op1) + && stack_top_dies + && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1)) + && REGNO (cmp_op1) != FIRST_STACK_REG) + { + /* 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 (eflags_p == 1) + { + /* There is no double popping fcomi variant. Fortunately, + eflags is immune from the fstp's cc clobbering. */ + if (unordered_p) + output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands); + else + output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands); + return "fstp\t%y0"; + } else { - xops[0] = operands[0]; - xops[1] = operands[4]; - output_asm_insn (output_move_double (xops), xops); + if (eflags_p == 2) + { + if (unordered_p) + return "fucompp\n\tfnstsw\t%0"; + else + return "fcompp\n\tfnstsw\t%0"; + } + else + { + if (unordered_p) + return "fucompp"; + else + return "fcompp"; + } } } + else + { + /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */ + + static const char * const alt[24] = + { + "fcom%z1\t%y1", + "fcomp%z1\t%y1", + "fucom%z1\t%y1", + "fucomp%z1\t%y1", + + "ficom%z1\t%y1", + "ficomp%z1\t%y1", + NULL, + NULL, + + "fcomi\t{%y1, %0|%0, %y1}", + "fcomip\t{%y1, %0|%0, %y1}", + "fucomi\t{%y1, %0|%0, %y1}", + "fucomip\t{%y1, %0|%0, %y1}", + + NULL, + NULL, + NULL, + NULL, + + "fcom%z2\t%y2\n\tfnstsw\t%0", + "fcomp%z2\t%y2\n\tfnstsw\t%0", + "fucom%z2\t%y2\n\tfnstsw\t%0", + "fucomp%z2\t%y2\n\tfnstsw\t%0", + + "ficom%z2\t%y2\n\tfnstsw\t%0", + "ficomp%z2\t%y2\n\tfnstsw\t%0", + NULL, + NULL + }; + + int mask; + const char *ret; + + mask = eflags_p << 3; + mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2; + mask |= unordered_p << 1; + mask |= stack_top_dies; + + if (mask >= 24) + abort (); + ret = alt[mask]; + if (ret == NULL) + abort (); - return AS1 (fldc%W2,%2); + return ret; + } +} + +void +ix86_output_addr_vec_elt (file, value) + FILE *file; + int value; +{ + const char *directive = ASM_LONG; + + if (TARGET_64BIT) + { +#ifdef ASM_QUAD + directive = ASM_QUAD; +#else + abort (); +#endif + } + + fprintf (file, "%s%s%d\n", directive, LPREFIX, value); +} + +void +ix86_output_addr_diff_elt (file, value, rel) + FILE *file; + int value, rel; +{ + if (TARGET_64BIT) + fprintf (file, "%s%s%d-.+4+(.-%s%d)\n", + ASM_LONG, LPREFIX, value, LPREFIX, rel); + else if (HAVE_AS_GOTOFF_IN_DATA) + fprintf (file, "%s%s%d@GOTOFF\n", ASM_LONG, LPREFIX, value); + else + asm_fprintf (file, "%s%U_GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", + ASM_LONG, LPREFIX, value); } -/* 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. */ +/* Generate either "mov $0, reg" or "xor reg, reg", as appropriate + for the target. */ void -output_float_extend (insn, operands) - rtx insn; - rtx *operands; +ix86_expand_clear (dest) + rtx dest; { - int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; - rtx xops[2]; + rtx tmp; - if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1])) + /* We play register width games, which are only valid after reload. */ + if (!reload_completed) abort (); - if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies) - return; + /* Avoid HImode and its attendant prefix byte. */ + if (GET_MODE_SIZE (GET_MODE (dest)) < 4) + dest = gen_rtx_REG (SImode, REGNO (dest)); - if (STACK_TOP_P (operands[0]) ) + tmp = gen_rtx_SET (VOIDmode, dest, const0_rtx); + + /* This predicate should match that for movsi_xor and movdi_xor_rex64. */ + if (reload_completed && (!TARGET_USE_MOV0 || optimize_size)) { - 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); - } - } + rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, 17)); + tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); + } - xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1]; + emit_insn (tmp); +} - output_asm_insn (AS1 (fld%z0,%y0), xops); - } - else +void +ix86_expand_move (mode, operands) + enum machine_mode mode; + rtx operands[]; +{ + int strict = (reload_in_progress || reload_completed); + rtx insn; + + if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode)) { - xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0]; + /* Emit insns to move operands[1] into operands[0]. */ - if (stack_top_dies - || (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode)) + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (Pmode, operands[1]); + else { - output_asm_insn (AS1 (fstp%z0,%y0), xops); - if (! stack_top_dies) - output_asm_insn (AS1 (fld%z0,%y0), xops); + rtx temp = operands[0]; + if (GET_CODE (temp) != REG) + temp = gen_reg_rtx (Pmode); + temp = legitimize_pic_address (operands[1], temp); + if (temp == operands[0]) + return; + operands[1] = temp; } - else - output_asm_insn (AS1 (fst%z0,%y0), xops); - - if (NON_STACK_REG_P (operands[0])) + } + else + { + if (GET_CODE (operands[0]) == MEM + && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode) + || !push_operand (operands[0], mode)) + && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (mode, operands[1]); + + if (push_operand (operands[0], mode) + && ! general_no_elim_operand (operands[1], mode)) + operands[1] = copy_to_mode_reg (mode, operands[1]); + + /* Force large constants in 64bit compilation into register + to get them CSEed. */ + if (TARGET_64BIT && mode == DImode + && immediate_operand (operands[1], mode) + && !x86_64_zero_extended_value (operands[1]) + && !register_operand (operands[0], mode) + && optimize && !reload_completed && !reload_in_progress) + operands[1] = copy_to_mode_reg (mode, operands[1]); + + if (FLOAT_MODE_P (mode)) { - xops[0] = operands[0]; - xops[1] = operands[3]; - output_asm_insn (output_move_double (xops), xops); + /* If we are loading a floating point constant to a register, + force the value to memory now, since we'll get better code + out the back end. */ + + if (strict) + ; + else if (GET_CODE (operands[1]) == CONST_DOUBLE + && register_operand (operands[0], mode)) + operands[1] = validize_mem (force_const_mem (mode, operands[1])); } } + + insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]); + + emit_insn (insn); } - -/* 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; +void +ix86_expand_vector_move (mode, operands) + enum machine_mode mode; + 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; + /* Force constants other than zero into memory. We do not know how + the instructions used to build constants modify the upper 64 bits + of the register, once we have that information we may be able + to handle some of them more efficiently. */ + if ((reload_in_progress | reload_completed) == 0 + && register_operand (operands[0], mode) + && CONSTANT_P (operands[1])) + { + rtx addr = gen_reg_rtx (Pmode); + emit_move_insn (addr, XEXP (force_const_mem (mode, operands[1]), 0)); + operands[1] = gen_rtx_MEM (mode, addr); + } + + /* Make operand1 a register if it isn't already. */ + if ((reload_in_progress | reload_completed) == 0 + && !register_operand (operands[0], mode) + && !register_operand (operands[1], mode) + && operands[1] != CONST0_RTX (mode)) + { + rtx temp = force_reg (TImode, operands[1]); + emit_move_insn (operands[0], temp); + return; + } + + emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); +} + +/* 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. */ - if (TARGET_CMOVE && STACK_REG_P (operands[1]) - && STACK_REG_P (operands[0])) +void +ix86_expand_binary_operator (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx operands[]; +{ + int matching_memory; + rtx src1, src2, dst, op, clob; + + dst = operands[0]; + src1 = operands[1]; + src2 = operands[2]; + + /* Recognize <var1> = <value> <op> <var1> for commutative operators */ + if (GET_RTX_CLASS (code) == 'c' + && (rtx_equal_p (dst, src2) + || immediate_operand (src1, mode))) { - cc_status.flags |= CC_FCOMI; - cc_prev_status.flags &= ~CC_TEST_AX; + rtx temp = src1; + src1 = src2; + src2 = temp; } - if (! STACK_TOP_P (operands[0])) + /* If the destination is memory, and we do not have matching source + operands, do things in registers. */ + matching_memory = 0; + if (GET_CODE (dst) == MEM) { - tmp = operands[0]; - operands[0] = operands[1]; - operands[1] = tmp; - cc_status.flags |= CC_REVERSED; + if (rtx_equal_p (dst, src1)) + matching_memory = 1; + else if (GET_RTX_CLASS (code) == 'c' + && rtx_equal_p (dst, src2)) + matching_memory = 2; + else + dst = gen_reg_rtx (mode); } - if (! STACK_TOP_P (operands[0])) - abort (); + /* Both source operands cannot be in memory. */ + if (GET_CODE (src1) == MEM && GET_CODE (src2) == MEM) + { + if (matching_memory != 2) + src2 = force_reg (mode, src2); + else + src1 = force_reg (mode, src1); + } - stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + /* If the operation is not commutable, source 1 cannot be a constant + or non-matching memory. */ + if ((CONSTANT_P (src1) + || (!matching_memory && GET_CODE (src1) == MEM)) + && GET_RTX_CLASS (code) != 'c') + src1 = force_reg (mode, src1); - 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 optimizing, copy to regs to improve CSE */ + if (optimize && ! no_new_pseudos) { - /* 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 (GET_CODE (dst) == MEM) + dst = gen_reg_rtx (mode); + if (GET_CODE (src1) == MEM) + src1 = force_reg (mode, src1); + if (GET_CODE (src2) == MEM) + src2 = force_reg (mode, src2); + } - if (unordered_compare) - { - if (cc_status.flags & CC_FCOMI) - { - output_asm_insn (AS2 (fucomip,%y1,%0), operands); - output_asm_insn (AS1 (fstp, %y0), operands); - if (!TARGET_IEEE_FP) - 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); - if (!TARGET_IEEE_FP) - cc0_set = 0; - } - else - output_asm_insn ("fcompp", operands); - } + /* Emit the instruction. */ + + op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, mode, src1, src2)); + if (reload_in_progress) + { + /* Reload doesn't know about the flags register, and doesn't know that + it doesn't want to clobber it. We can only do this with PLUS. */ + if (code != PLUS) + abort (); + emit_insn (op); } else { - static char buf[100]; + clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); + } - /* Decide if this is a float compare or an unordered float compare. */ + /* Fix up the destination if needed. */ + if (dst != operands[0]) + emit_move_insn (operands[0], dst); +} - if (unordered_compare) - strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom"); - else - strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom"); +/* 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]; +{ + /* Both source operands cannot be in memory. */ + if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) + return 0; + /* If the operation is not commutable, source 1 cannot be a constant. */ + if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != 'c') + return 0; + /* If the destination is memory, we must have a matching source operand. */ + if (GET_CODE (operands[0]) == MEM + && ! (rtx_equal_p (operands[0], operands[1]) + || (GET_RTX_CLASS (code) == 'c' + && rtx_equal_p (operands[0], operands[2])))) + return 0; + /* If the operation is not commutable and the source 1 is memory, we must + have a matching destination. */ + if (GET_CODE (operands[1]) == MEM + && GET_RTX_CLASS (code) != 'c' + && ! rtx_equal_p (operands[0], operands[1])) + return 0; + return 1; +} - /* Modify the opcode if the 387 stack is to be popped. */ +/* 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. */ - if (stack_top_dies) - strcat (buf, "p"); +void +ix86_expand_unary_operator (code, mode, operands) + enum rtx_code code; + enum machine_mode mode; + rtx operands[]; +{ + int matching_memory; + rtx src, dst, op, clob; - if (cc_status.flags & CC_FCOMI) - { - output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands); - if (!TARGET_IEEE_FP) - cc0_set = 0; - } + dst = operands[0]; + src = operands[1]; + + /* If the destination is memory, and we do not have matching source + operands, do things in registers. */ + matching_memory = 0; + if (GET_CODE (dst) == MEM) + { + if (rtx_equal_p (dst, src)) + matching_memory = 1; else - output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands); + dst = gen_reg_rtx (mode); } - /* Now retrieve the condition code. */ - if (cc0_set) + /* When source operand is memory, destination must match. */ + if (!matching_memory && GET_CODE (src) == MEM) + src = force_reg (mode, src); + + /* If optimizing, copy to regs to improve CSE */ + if (optimize && ! no_new_pseudos) { - char *r = output_fp_cc0_set (insn); - if (r[0]) output_asm_insn (r, operands); + if (GET_CODE (dst) == MEM) + dst = gen_reg_rtx (mode); + if (GET_CODE (src) == MEM) + src = force_reg (mode, src); } + /* Emit the instruction. */ - /* We emit fstp instruction after integer comparsions to improve - scheduling. */ - for (i = 0; i < 2 ; i++) + op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_e (code, mode, src)); + if (reload_in_progress || code == NOT) { - 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[2]; - xexp[0] = gen_rtx_REG (DFmode, - REGNO (operands[i]) - (stack_top_dies != 0)); - output_asm_insn (AS1 (fstp, %y0), xexp); - } + /* Reload doesn't know about the flags register, and doesn't know that + it doesn't want to clobber it. */ + if (code != NOT) + abort (); + emit_insn (op); + } + else + { + clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); } - return ""; + /* Fix up the destination if needed. */ + if (dst != operands[0]) + emit_move_insn (operands[0], dst); +} +/* 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; +{ + /* If one of operands is memory, source and destination must match. */ + if ((GET_CODE (operands[0]) == MEM + || GET_CODE (operands[1]) == MEM) + && ! rtx_equal_p (operands[0], operands[1])) + return FALSE; + return TRUE; } - -/* 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) +/* Return TRUE or FALSE depending on whether the first SET in INSN + has source and destination with matching CC modes, and that the + CC mode is at least as constrained as REQ_MODE. */ + +int +ix86_match_ccmode (insn, req_mode) rtx insn; + enum machine_mode req_mode; { - rtx xops[3]; - rtx next; - enum rtx_code code; + rtx set; + enum machine_mode set_mode; - if (!(cc_status.flags & CC_FCOMI)) - { - xops[0] = gen_rtx_REG (HImode, 0); - output_asm_insn (AS1 (fnsts%W0,%0), xops); - } + set = PATTERN (insn); + if (GET_CODE (set) == PARALLEL) + set = XVECEXP (set, 0, 0); + if (GET_CODE (set) != SET) + abort (); + if (GET_CODE (SET_SRC (set)) != COMPARE) + abort (); - if (! TARGET_IEEE_FP) + set_mode = GET_MODE (SET_DEST (set)); + switch (set_mode) { - if (!(cc_status.flags & CC_REVERSED)) - { - next = next_cc0_user (insn); - - if (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 ""; - } - } + case CCNOmode: + if (req_mode != CCNOmode + && (req_mode != CCmode + || XEXP (SET_SRC (set), 1) != const0_rtx)) + return 0; + break; + case CCmode: + if (req_mode == CCGCmode) + return 0; + /* FALLTHRU */ + case CCGCmode: + if (req_mode == CCGOCmode || req_mode == CCNOmode) + return 0; + /* FALLTHRU */ + case CCGOCmode: + if (req_mode == CCZmode) + return 0; + /* FALLTHRU */ + case CCZmode: + break; - return "sahf"; + default: + abort (); } - next = next_cc0_user (insn); - if (next == NULL_RTX) - abort (); + return (GET_MODE (SET_SRC (set)) == set_mode); +} - if (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) +/* Generate insn patterns to do an integer compare of OPERANDS. */ + +static rtx +ix86_expand_int_compare (code, op0, op1) + enum rtx_code code; + rtx op0, op1; +{ + enum machine_mode cmpmode; + rtx tmp, flags; + + cmpmode = SELECT_CC_MODE (code, op0, op1); + flags = gen_rtx_REG (cmpmode, FLAGS_REG); + + /* This is very simple, but making the interface the same as in the + FP case makes the rest of the code easier. */ + tmp = gen_rtx_COMPARE (cmpmode, op0, op1); + emit_insn (gen_rtx_SET (VOIDmode, flags, tmp)); + + /* Return the test that should be put into the flags user, i.e. + the bcc, scc, or cmov instruction. */ + return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx); +} + +/* Figure out whether to use ordered or unordered fp comparisons. + Return the appropriate mode to use. */ + +enum machine_mode +ix86_fp_compare_mode (code) + enum rtx_code code ATTRIBUTE_UNUSED; +{ + /* ??? In order to make all comparisons reversible, we do all comparisons + non-trapping when compiling for IEEE. Once gcc is able to distinguish + all forms trapping and nontrapping comparisons, we can make inequality + comparisons trapping again, since it results in better code when using + FCOM based compares. */ + return TARGET_IEEE_FP ? CCFPUmode : CCFPmode; +} + +enum machine_mode +ix86_cc_mode (code, op0, op1) + enum rtx_code code; + rtx op0, op1; +{ + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) + return ix86_fp_compare_mode (code); + switch (code) { - if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE) - code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0)); + /* Only zero flag is needed. */ + case EQ: /* ZF=0 */ + case NE: /* ZF!=0 */ + return CCZmode; + /* Codes needing carry flag. */ + case GEU: /* CF=0 */ + case GTU: /* CF=0 & ZF=0 */ + case LTU: /* CF=1 */ + case LEU: /* CF=1 | ZF=1 */ + return CCmode; + /* Codes possibly doable only with sign flag when + comparing against zero. */ + case GE: /* SF=OF or SF=0 */ + case LT: /* SF<>OF or SF=1 */ + if (op1 == const0_rtx) + return CCGOCmode; else - code = GET_CODE (SET_SRC (PATTERN (next))); + /* For other cases Carry flag is not required. */ + return CCGCmode; + /* Codes doable only with sign flag when comparing + against zero, but we miss jump instruction for it + so we need to use relational tests agains overflow + that thus needs to be zero. */ + case GT: /* ZF=0 & SF=OF */ + case LE: /* ZF=1 | SF<>OF */ + if (op1 == const0_rtx) + return CCNOmode; + else + return CCGCmode; + /* strcmp pattern do (use flags) and combine may ask us for proper + mode. */ + case USE: + return CCmode; + default: + abort (); } +} + +/* Return true if we should use an FCOMI instruction for this fp comparison. */ - else if (GET_CODE (PATTERN (next)) == PARALLEL - && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET) +int +ix86_use_fcomi_compare (code) + enum rtx_code code ATTRIBUTE_UNUSED; +{ + enum rtx_code swapped_code = swap_condition (code); + return ((ix86_fp_comparison_cost (code) == ix86_fp_comparison_fcomi_cost (code)) + || (ix86_fp_comparison_cost (swapped_code) + == ix86_fp_comparison_fcomi_cost (swapped_code))); +} + +/* Swap, force into registers, or otherwise massage the two operands + to a fp comparison. The operands are updated in place; the new + comparsion code is returned. */ + +static enum rtx_code +ix86_prepare_fp_compare_args (code, pop0, pop1) + enum rtx_code code; + rtx *pop0, *pop1; +{ + enum machine_mode fpcmp_mode = ix86_fp_compare_mode (code); + rtx op0 = *pop0, op1 = *pop1; + enum machine_mode op_mode = GET_MODE (op0); + int is_sse = SSE_REG_P (op0) | SSE_REG_P (op1); + + /* All of the unordered compare instructions only work on registers. + The same is true of the XFmode compare instructions. The same is + true of the fcomi compare instructions. */ + + if (!is_sse + && (fpcmp_mode == CCFPUmode + || op_mode == XFmode + || op_mode == TFmode + || ix86_use_fcomi_compare (code))) { - 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))); + op0 = force_reg (op_mode, op0); + op1 = force_reg (op_mode, op1); } else - abort (); - - if (cc_status.flags & CC_FCOMI) { - /* It is very tricky. We have to do it right. */ + /* %%% We only allow op1 in memory; op0 must be st(0). So swap + things around if they appear profitable, otherwise force op0 + into a register. */ - xops [0] = gen_rtx_REG (QImode, 0); + if (standard_80387_constant_p (op0) == 0 + || (GET_CODE (op0) == MEM + && ! (standard_80387_constant_p (op1) == 0 + || GET_CODE (op1) == MEM))) + { + rtx tmp; + tmp = op0, op0 = op1, op1 = tmp; + code = swap_condition (code); + } - switch (code) + if (GET_CODE (op0) != REG) + op0 = force_reg (op_mode, op0); + + if (CONSTANT_P (op1)) { - case GT: - case GE: - break; + if (standard_80387_constant_p (op1)) + op1 = force_reg (op_mode, op1); + else + op1 = validize_mem (force_const_mem (op_mode, op1)); + } + } - case LT: - output_asm_insn (AS1 (setb,%b0), xops); - output_asm_insn (AS1 (setp,%h0), xops); - output_asm_insn (AS2 (cmp%B0,%b0,%h0), xops); - break; + /* Try to rearrange the comparison to make it cheaper. */ + if (ix86_fp_comparison_cost (code) + > ix86_fp_comparison_cost (swap_condition (code)) + && (GET_CODE (op0) == REG || !reload_completed)) + { + rtx tmp; + tmp = op0, op0 = op1, op1 = tmp; + code = swap_condition (code); + if (GET_CODE (op0) != REG) + op0 = force_reg (op_mode, op0); + } - case LE: - output_asm_insn (AS1 (setbe,%b0), xops); - output_asm_insn (AS1 (setnp,%h0), xops); - output_asm_insn (AS2 (xor%B0,%b0,%h0), xops); - break; + *pop0 = op0; + *pop1 = op1; + return code; +} - case EQ: - case NE: - output_asm_insn (AS1 (setne,%b0), xops); - output_asm_insn (AS1 (setp,%h0), xops); - output_asm_insn (AS2 (or%B0,%b0,%h0), xops); - break; +/* Convert comparison codes we use to represent FP comparison to integer + code that will result in proper branch. Return UNKNOWN if no such code + is available. */ +static enum rtx_code +ix86_fp_compare_code_to_integer (code) + enum rtx_code code; +{ + switch (code) + { + case GT: + return GTU; + case GE: + return GEU; + case ORDERED: + case UNORDERED: + return code; + break; + case UNEQ: + return EQ; + break; + case UNLT: + return LTU; + break; + case UNLE: + return LEU; + break; + case LTGT: + return NE; + break; + default: + return UNKNOWN; + } +} - case GTU: - case LTU: - case GEU: - case LEU: - default: - abort (); +/* Split comparison code CODE into comparisons we can do using branch + instructions. BYPASS_CODE is comparison code for branch that will + branch around FIRST_CODE and SECOND_CODE. If some of branches + is not required, set value to NIL. + We never require more than two branches. */ +static void +ix86_fp_comparison_codes (code, bypass_code, first_code, second_code) + enum rtx_code code, *bypass_code, *first_code, *second_code; +{ + *first_code = code; + *bypass_code = NIL; + *second_code = NIL; + + /* The fcomi comparison sets flags as follows: + + cmp ZF PF CF + > 0 0 0 + < 0 0 1 + = 1 0 0 + un 1 1 1 */ + + switch (code) + { + case GT: /* GTU - CF=0 & ZF=0 */ + case GE: /* GEU - CF=0 */ + case ORDERED: /* PF=0 */ + case UNORDERED: /* PF=1 */ + case UNEQ: /* EQ - ZF=1 */ + case UNLT: /* LTU - CF=1 */ + case UNLE: /* LEU - CF=1 | ZF=1 */ + case LTGT: /* EQ - ZF=0 */ + break; + case LT: /* LTU - CF=1 - fails on unordered */ + *first_code = UNLT; + *bypass_code = UNORDERED; + break; + case LE: /* LEU - CF=1 | ZF=1 - fails on unordered */ + *first_code = UNLE; + *bypass_code = UNORDERED; + break; + case EQ: /* EQ - ZF=1 - fails on unordered */ + *first_code = UNEQ; + *bypass_code = UNORDERED; + break; + case NE: /* NE - ZF=0 - fails on unordered */ + *first_code = LTGT; + *second_code = UNORDERED; + break; + case UNGE: /* GEU - CF=0 - fails on unordered */ + *first_code = GE; + *second_code = UNORDERED; + break; + case UNGT: /* GTU - CF=0 & ZF=0 - fails on unordered */ + *first_code = GT; + *second_code = UNORDERED; + break; + default: + abort (); + } + if (!TARGET_IEEE_FP) + { + *second_code = NIL; + *bypass_code = NIL; + } +} + +/* Return cost of comparison done fcom + arithmetics operations on AX. + All following functions do use number of instructions as an cost metrics. + In future this should be tweaked to compute bytes for optimize_size and + take into account performance of various instructions on various CPUs. */ +static int +ix86_fp_comparison_arithmetics_cost (code) + enum rtx_code code; +{ + if (!TARGET_IEEE_FP) + return 4; + /* The cost of code output by ix86_expand_fp_compare. */ + switch (code) + { + case UNLE: + case UNLT: + case LTGT: + case GT: + case GE: + case UNORDERED: + case ORDERED: + case UNEQ: + return 4; + break; + case LT: + case NE: + case EQ: + case UNGE: + return 5; + break; + case LE: + case UNGT: + return 6; + break; + default: + abort (); + } +} + +/* Return cost of comparison done using fcomi operation. + See ix86_fp_comparison_arithmetics_cost for the metrics. */ +static int +ix86_fp_comparison_fcomi_cost (code) + enum rtx_code code; +{ + enum rtx_code bypass_code, first_code, second_code; + /* Return arbitarily high cost when instruction is not supported - this + prevents gcc from using it. */ + if (!TARGET_CMOVE) + return 1024; + ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); + return (bypass_code != NIL || second_code != NIL) + 2; +} + +/* Return cost of comparison done using sahf operation. + See ix86_fp_comparison_arithmetics_cost for the metrics. */ +static int +ix86_fp_comparison_sahf_cost (code) + enum rtx_code code; +{ + enum rtx_code bypass_code, first_code, second_code; + /* Return arbitarily high cost when instruction is not preferred - this + avoids gcc from using it. */ + if (!TARGET_USE_SAHF && !optimize_size) + return 1024; + ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); + return (bypass_code != NIL || second_code != NIL) + 3; +} + +/* Compute cost of the comparison done using any method. + See ix86_fp_comparison_arithmetics_cost for the metrics. */ +static int +ix86_fp_comparison_cost (code) + enum rtx_code code; +{ + int fcomi_cost, sahf_cost, arithmetics_cost = 1024; + int min; + + fcomi_cost = ix86_fp_comparison_fcomi_cost (code); + sahf_cost = ix86_fp_comparison_sahf_cost (code); + + min = arithmetics_cost = ix86_fp_comparison_arithmetics_cost (code); + if (min > sahf_cost) + min = sahf_cost; + if (min > fcomi_cost) + min = fcomi_cost; + return min; +} + +/* Generate insn patterns to do a floating point compare of OPERANDS. */ + +static rtx +ix86_expand_fp_compare (code, op0, op1, scratch, second_test, bypass_test) + enum rtx_code code; + rtx op0, op1, scratch; + rtx *second_test; + rtx *bypass_test; +{ + enum machine_mode fpcmp_mode, intcmp_mode; + rtx tmp, tmp2; + int cost = ix86_fp_comparison_cost (code); + enum rtx_code bypass_code, first_code, second_code; + + fpcmp_mode = ix86_fp_compare_mode (code); + code = ix86_prepare_fp_compare_args (code, &op0, &op1); + + if (second_test) + *second_test = NULL_RTX; + if (bypass_test) + *bypass_test = NULL_RTX; + + ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); + + /* Do fcomi/sahf based test when profitable. */ + if ((bypass_code == NIL || bypass_test) + && (second_code == NIL || second_test) + && ix86_fp_comparison_arithmetics_cost (code) > cost) + { + if (TARGET_CMOVE) + { + tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1); + tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), + tmp); + emit_insn (tmp); + } + else + { + tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1); + tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9); + if (!scratch) + scratch = gen_reg_rtx (HImode); + emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp2)); + emit_insn (gen_x86_sahf_1 (scratch)); } + + /* The FP codes work out to act like unsigned. */ + intcmp_mode = fpcmp_mode; + code = first_code; + if (bypass_code != NIL) + *bypass_test = gen_rtx_fmt_ee (bypass_code, VOIDmode, + gen_rtx_REG (intcmp_mode, FLAGS_REG), + const0_rtx); + if (second_code != NIL) + *second_test = gen_rtx_fmt_ee (second_code, VOIDmode, + gen_rtx_REG (intcmp_mode, FLAGS_REG), + const0_rtx); } else { - xops[0] = gen_rtx_REG (QImode, 0); + /* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first. */ + tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1); + tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9); + if (!scratch) + scratch = gen_reg_rtx (HImode); + emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp2)); + + /* In the unordered case, we have to check C2 for NaN's, which + doesn't happen to work out to anything nice combination-wise. + So do some bit twiddling on the value we've got in AH to come + up with an appropriate set of condition codes. */ + intcmp_mode = CCNOmode; switch (code) { case GT: - xops[1] = GEN_INT (0x45); - output_asm_insn (AS2 (and%B0,%1,%h0), xops); - /* je label */ + case UNGT: + if (code == GT || !TARGET_IEEE_FP) + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45))); + code = EQ; + } + else + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx)); + emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x44))); + intcmp_mode = CCmode; + code = GEU; + } 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 */ + case UNLT: + if (code == LT && TARGET_IEEE_FP) + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x01))); + intcmp_mode = CCmode; + code = EQ; + } + else + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x01))); + code = NE; + } break; - case GE: - xops[1] = GEN_INT (0x05); - output_asm_insn (AS2 (and%B0,%1,%h0), xops); - /* je label */ + case UNGE: + if (code == GE || !TARGET_IEEE_FP) + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x05))); + code = EQ; + } + else + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch, + GEN_INT (0x01))); + code = NE; + } 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 */ + case UNLE: + if (code == LE && TARGET_IEEE_FP) + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx)); + emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40))); + intcmp_mode = CCmode; + code = LTU; + } + else + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45))); + code = NE; + } 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 */ + case UNEQ: + if (code == EQ && TARGET_IEEE_FP) + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40))); + intcmp_mode = CCmode; + code = EQ; + } + else + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40))); + code = NE; + break; + } 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 */ + case LTGT: + if (code == NE && TARGET_IEEE_FP) + { + emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45))); + emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch, + GEN_INT (0x40))); + code = NE; + } + else + { + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40))); + code = EQ; + } + break; + + case UNORDERED: + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04))); + code = NE; + break; + case ORDERED: + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04))); + code = EQ; break; - case GTU: - case LTU: - case GEU: - case LEU: default: abort (); } } - return ""; + /* Return the test that should be put into the flags user, i.e. + the bcc, scc, or cmov instruction. */ + return gen_rtx_fmt_ee (code, VOIDmode, + gen_rtx_REG (intcmp_mode, FLAGS_REG), + const0_rtx); } - -#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 +ix86_expand_compare (code, second_test, bypass_test) + enum rtx_code code; + rtx *second_test, *bypass_test; { - rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; - rtx pic_label_rtx; - char pic_label_name[256]; -}; + rtx op0, op1, ret; + op0 = ix86_compare_op0; + op1 = ix86_compare_op1; + + if (second_test) + *second_test = NULL_RTX; + if (bypass_test) + *bypass_test = NULL_RTX; + + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) + ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX, + second_test, bypass_test); + else + ret = ix86_expand_int_compare (code, op0, op1); -/* Functions to save and restore i386_stack_locals. - These will be called, via pointer variables, - from push_function_context and pop_function_context. */ + return ret; +} -void -save_386_machine_status (p) - struct function *p; +/* Return true if the CODE will result in nontrivial jump sequence. */ +bool +ix86_fp_jump_nontrivial_p (code) + enum rtx_code code; { - 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); + enum rtx_code bypass_code, first_code, second_code; + if (!TARGET_CMOVE) + return true; + ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); + return bypass_code != NIL || second_code != NIL; } void -restore_386_machine_status (p) - struct function *p; +ix86_expand_branch (code, label) + enum rtx_code code; + rtx label; { - 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; -} + rtx tmp; -/* Clear stack slot assignments remembered from previous functions. - This is called from INIT_EXPANDERS once before RTL is emitted for each - function. */ + switch (GET_MODE (ix86_compare_op0)) + { + case QImode: + case HImode: + case SImode: + simple: + tmp = ix86_expand_compare (code, NULL, NULL); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + return; -void -clear_386_stack_locals () -{ - enum machine_mode mode; - int n; + case SFmode: + case DFmode: + case XFmode: + case TFmode: + { + rtvec vec; + int use_fcomi; + enum rtx_code bypass_code, first_code, second_code; + + code = ix86_prepare_fp_compare_args (code, &ix86_compare_op0, + &ix86_compare_op1); + + ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code); + + /* Check whether we will use the natural sequence with one jump. If + so, we can expand jump early. Otherwise delay expansion by + creating compound insn to not confuse optimizers. */ + if (bypass_code == NIL && second_code == NIL + && TARGET_CMOVE) + { + ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx, NULL_RTX); + } + else + { + tmp = gen_rtx_fmt_ee (code, VOIDmode, + ix86_compare_op0, ix86_compare_op1); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp); + + use_fcomi = ix86_use_fcomi_compare (code); + vec = rtvec_alloc (3 + !use_fcomi); + RTVEC_ELT (vec, 0) = tmp; + RTVEC_ELT (vec, 1) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18)); + RTVEC_ELT (vec, 2) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17)); + if (! use_fcomi) + RTVEC_ELT (vec, 3) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode)); + + emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec)); + } + return; + } - 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; + case DImode: + if (TARGET_64BIT) + goto simple; + /* Expand DImode branch into multiple compare+branch. */ + { + rtx lo[2], hi[2], label2; + enum rtx_code code1, code2, code3; - 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; -} + if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1)) + { + tmp = ix86_compare_op0; + ix86_compare_op0 = ix86_compare_op1; + ix86_compare_op1 = tmp; + code = swap_condition (code); + } + split_di (&ix86_compare_op0, 1, lo+0, hi+0); + split_di (&ix86_compare_op1, 1, lo+1, hi+1); -/* Return a MEM corresponding to a stack slot with mode MODE. - Allocate a new slot if necessary. + /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to + avoid two branches. This costs one extra insn, so disable when + optimizing for size. */ - The RTL for a function can have several slots available: N is - which slot to use. */ + if ((code == EQ || code == NE) + && (!optimize_size + || hi[1] == const0_rtx || lo[1] == const0_rtx)) + { + rtx xor0, xor1; -rtx -assign_386_stack_local (mode, n) - enum machine_mode mode; - int n; -{ - if (n < 0 || n >= MAX_386_STACK_LOCALS) - abort (); + xor1 = hi[0]; + if (hi[1] != const0_rtx) + xor1 = expand_binop (SImode, xor_optab, xor1, hi[1], + NULL_RTX, 0, OPTAB_WIDEN); - if (i386_stack_locals[(int) mode][n] == NULL_RTX) - i386_stack_locals[(int) mode][n] - = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); + xor0 = lo[0]; + if (lo[1] != const0_rtx) + xor0 = expand_binop (SImode, xor_optab, xor0, lo[1], + NULL_RTX, 0, OPTAB_WIDEN); - 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); + tmp = expand_binop (SImode, ior_optab, xor1, xor0, + NULL_RTX, 0, OPTAB_WIDEN); + + ix86_compare_op0 = tmp; + ix86_compare_op1 = const0_rtx; + ix86_expand_branch (code, label); + return; + } + + /* Otherwise, if we are doing less-than or greater-or-equal-than, + op1 is a constant and the low word is zero, then we can just + examine the high word. */ + + if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx) + switch (code) + { + case LT: case LTU: case GE: case GEU: + ix86_compare_op0 = hi[0]; + ix86_compare_op1 = hi[1]; + ix86_expand_branch (code, label); + return; + default: + break; + } + + /* Otherwise, we need two or three jumps. */ + + label2 = gen_label_rtx (); + + code1 = code; + code2 = swap_condition (code); + code3 = unsigned_condition (code); + + switch (code) + { + case LT: case GT: case LTU: case GTU: + break; + + case LE: code1 = LT; code2 = GT; break; + case GE: code1 = GT; code2 = LT; break; + case LEU: code1 = LTU; code2 = GTU; break; + case GEU: code1 = GTU; code2 = LTU; break; + + case EQ: code1 = NIL; code2 = NE; break; + case NE: code2 = NIL; break; + + default: + abort (); + } + + /* + * a < b => + * if (hi(a) < hi(b)) goto true; + * if (hi(a) > hi(b)) goto false; + * if (lo(a) < lo(b)) goto true; + * false: + */ + + ix86_compare_op0 = hi[0]; + ix86_compare_op1 = hi[1]; + + if (code1 != NIL) + ix86_expand_branch (code1, label); + if (code2 != NIL) + ix86_expand_branch (code2, label2); + + ix86_compare_op0 = lo[0]; + ix86_compare_op1 = lo[1]; + ix86_expand_branch (code3, label); + + if (code2 != NIL) + emit_label (label2); + return; + } + + default: + abort (); + } } -int is_div(op,mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +/* Split branch based on floating point condition. */ +void +ix86_split_fp_branch (code, op1, op2, target1, target2, tmp) + enum rtx_code code; + rtx op1, op2, target1, target2, tmp; { - return (GET_CODE (op) == DIV); + rtx second, bypass; + rtx label = NULL_RTX; + rtx condition; + int bypass_probability = -1, second_probability = -1, probability = -1; + rtx i; + + if (target2 != pc_rtx) + { + rtx tmp = target2; + code = reverse_condition_maybe_unordered (code); + target2 = target1; + target1 = tmp; + } + + condition = ix86_expand_fp_compare (code, op1, op2, + tmp, &second, &bypass); + + if (split_branch_probability >= 0) + { + /* Distribute the probabilities across the jumps. + Assume the BYPASS and SECOND to be always test + for UNORDERED. */ + probability = split_branch_probability; + + /* Value of 1 is low enough to make no need for probability + to be updated. Later we may run some experiments and see + if unordered values are more frequent in practice. */ + if (bypass) + bypass_probability = 1; + if (second) + second_probability = 1; + } + if (bypass != NULL_RTX) + { + label = gen_label_rtx (); + i = emit_jump_insn (gen_rtx_SET + (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + bypass, + gen_rtx_LABEL_REF (VOIDmode, + label), + pc_rtx))); + if (bypass_probability >= 0) + REG_NOTES (i) + = gen_rtx_EXPR_LIST (REG_BR_PROB, + GEN_INT (bypass_probability), + REG_NOTES (i)); + } + i = emit_jump_insn (gen_rtx_SET + (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + condition, target1, target2))); + if (probability >= 0) + REG_NOTES (i) + = gen_rtx_EXPR_LIST (REG_BR_PROB, + GEN_INT (probability), + REG_NOTES (i)); + if (second != NULL_RTX) + { + i = emit_jump_insn (gen_rtx_SET + (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, second, target1, + target2))); + if (second_probability >= 0) + REG_NOTES (i) + = gen_rtx_EXPR_LIST (REG_BR_PROB, + GEN_INT (second_probability), + REG_NOTES (i)); + } + if (label != NULL_RTX) + emit_label (label); } - -#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; +int +ix86_expand_setcc (code, dest) + enum rtx_code code; + rtx dest; { - register rtx copy; - register int i, j; - register RTX_CODE code; - register char *format_ptr; + rtx ret, tmp, tmpreg; + rtx second_test, bypass_test; - code = GET_CODE (orig); + if (GET_MODE (ix86_compare_op0) == DImode + && !TARGET_64BIT) + return 0; /* FAIL */ - switch (code) + if (GET_MODE (dest) != QImode) + abort (); + + ret = ix86_expand_compare (code, &second_test, &bypass_test); + PUT_MODE (ret, QImode); + + tmp = dest; + tmpreg = dest; + + emit_insn (gen_rtx_SET (VOIDmode, tmp, ret)); + if (bypass_test || second_test) { - 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; + rtx test = second_test; + int bypass = 0; + rtx tmp2 = gen_reg_rtx (QImode); + if (bypass_test) + { + if (second_test) + abort (); + test = bypass_test; + bypass = 1; + PUT_CODE (test, reverse_condition_maybe_unordered (GET_CODE (test))); + } + PUT_MODE (test, QImode); + emit_insn (gen_rtx_SET (VOIDmode, tmp2, test)); -#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. */ + if (bypass) + emit_insn (gen_andqi3 (tmp, tmpreg, tmp2)); + else + emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2)); + } + + return 1; /* DONE */ +} + +int +ix86_expand_int_movcc (operands) + rtx operands[]; +{ + enum rtx_code code = GET_CODE (operands[1]), compare_code; + rtx compare_seq, compare_op; + rtx second_test, bypass_test; + enum machine_mode mode = GET_MODE (operands[0]); + + /* When the compare code is not LTU or GEU, we can not use sbbl case. + In case comparsion is done with immediate, we can convert it to LTU or + GEU by altering the integer. */ + + if ((code == LEU || code == GTU) + && GET_CODE (ix86_compare_op1) == CONST_INT + && mode != HImode + && (unsigned int) INTVAL (ix86_compare_op1) != 0xffffffff + && GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT) + { + if (code == LEU) + code = LTU; + else + code = GEU; + ix86_compare_op1 = GEN_INT (INTVAL (ix86_compare_op1) + 1); } - 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; + start_sequence (); + compare_op = ix86_expand_compare (code, &second_test, &bypass_test); + compare_seq = gen_sequence (); + end_sequence (); + + compare_code = GET_CODE (compare_op); - format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); + /* Don't attempt mode expansion here -- if we had to expand 5 or 6 + HImode insns, we'd be swallowed in word prefix ops. */ - for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++) + if (mode != HImode + && (mode != DImode || TARGET_64BIT) + && GET_CODE (operands[2]) == CONST_INT + && GET_CODE (operands[3]) == CONST_INT) { - switch (*format_ptr++) + rtx out = operands[0]; + HOST_WIDE_INT ct = INTVAL (operands[2]); + HOST_WIDE_INT cf = INTVAL (operands[3]); + HOST_WIDE_INT diff; + + if ((compare_code == LTU || compare_code == GEU) + && !second_test && !bypass_test) { - 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; + /* Detect overlap between destination and compare sources. */ + rtx tmp = out; - case 'E': - case 'V': - XVEC (copy, i) = XVEC (orig, i); - if (XVEC (orig, i) != NULL) + /* To simplify rest of code, restrict to the GEU case. */ + if (compare_code == LTU) { - 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)); + int tmp = ct; + ct = cf; + cf = tmp; + compare_code = reverse_condition (compare_code); + code = reverse_condition (code); } - break; + diff = ct - cf; - case 'w': - XWINT (copy, i) = XWINT (orig, i); - break; + if (reg_overlap_mentioned_p (out, ix86_compare_op0) + || reg_overlap_mentioned_p (out, ix86_compare_op1)) + tmp = gen_reg_rtx (mode); - case 'i': - XINT (copy, i) = XINT (orig, i); - break; + emit_insn (compare_seq); + if (mode == DImode) + emit_insn (gen_x86_movdicc_0_m1_rex64 (tmp)); + else + emit_insn (gen_x86_movsicc_0_m1 (tmp)); - case 's': - case 'S': - XSTR (copy, i) = XSTR (orig, i); - break; + if (diff == 1) + { + /* + * cmpl op0,op1 + * sbbl dest,dest + * [addl dest, ct] + * + * Size 5 - 8. + */ + if (ct) + tmp = expand_simple_binop (mode, PLUS, + tmp, GEN_INT (ct), + tmp, 1, OPTAB_DIRECT); + } + else if (cf == -1) + { + /* + * cmpl op0,op1 + * sbbl dest,dest + * orl $ct, dest + * + * Size 8. + */ + tmp = expand_simple_binop (mode, IOR, + tmp, GEN_INT (ct), + tmp, 1, OPTAB_DIRECT); + } + else if (diff == -1 && ct) + { + /* + * cmpl op0,op1 + * sbbl dest,dest + * xorl $-1, dest + * [addl dest, cf] + * + * Size 8 - 11. + */ + tmp = expand_simple_unop (mode, NOT, tmp, tmp, 1); + if (cf) + tmp = expand_simple_binop (mode, PLUS, + tmp, GEN_INT (cf), + tmp, 1, OPTAB_DIRECT); + } + else + { + /* + * cmpl op0,op1 + * sbbl dest,dest + * andl cf - ct, dest + * [addl dest, ct] + * + * Size 8 - 11. + */ + tmp = expand_simple_binop (mode, AND, + tmp, + GEN_INT (trunc_int_for_mode + (cf - ct, mode)), + tmp, 1, OPTAB_DIRECT); + if (ct) + tmp = expand_simple_binop (mode, PLUS, + tmp, GEN_INT (ct), + tmp, 1, OPTAB_DIRECT); + } - default: - abort (); + if (tmp != out) + emit_move_insn (out, tmp); + + return 1; /* DONE */ } - } - return copy; -} - -/* Try to rewrite a memory address to make it valid */ + diff = ct - cf; + if (diff < 0) + { + HOST_WIDE_INT tmp; + tmp = ct, ct = cf, cf = tmp; + diff = -diff; + if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0))) + { + /* We may be reversing unordered compare to normal compare, that + is not valid in general (we may convert non-trapping condition + to trapping one), however on i386 we currently emit all + comparisons unordered. */ + compare_code = reverse_condition_maybe_unordered (compare_code); + code = reverse_condition_maybe_unordered (code); + } + else + { + compare_code = reverse_condition (compare_code); + code = reverse_condition (code); + } + } + if ((diff == 1 || diff == 2 || diff == 4 || diff == 8 + || diff == 3 || diff == 5 || diff == 9) + && (mode != DImode || x86_64_sign_extended_value (GEN_INT (cf)))) + { + /* + * xorl dest,dest + * cmpl op1,op2 + * setcc dest + * lea cf(dest*(ct-cf)),dest + * + * Size 14. + * + * This also catches the degenerate setcc-only case. + */ + + rtx tmp; + int nops; + + out = emit_store_flag (out, code, ix86_compare_op0, + ix86_compare_op1, VOIDmode, 0, 1); + + nops = 0; + /* On x86_64 the lea instruction operates on Pmode, so we need to get arithmetics + done in proper mode to match. */ + if (diff == 1) + tmp = out; + else + { + rtx out1; + out1 = out; + tmp = gen_rtx_MULT (mode, out1, GEN_INT (diff & ~1)); + nops++; + if (diff & 1) + { + tmp = gen_rtx_PLUS (mode, tmp, out1); + nops++; + } + } + if (cf != 0) + { + tmp = gen_rtx_PLUS (mode, tmp, GEN_INT (cf)); + nops++; + } + if (tmp != out + && (GET_CODE (tmp) != SUBREG || SUBREG_REG (tmp) != out)) + { + if (nops == 1) + { + rtx clob; -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; + clob = gen_rtx_REG (CCmode, FLAGS_REG); + clob = gen_rtx_CLOBBER (VOIDmode, clob); + + tmp = gen_rtx_SET (VOIDmode, out, tmp); + tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); + emit_insn (tmp); + } + else + emit_insn (gen_rtx_SET (VOIDmode, out, tmp)); + } + if (out != operands[0]) + emit_move_insn (operands[0], out); + + return 1; /* DONE */ } - obfree (storage); - } + /* + * General case: Jumpful: + * xorl dest,dest cmpl op1, op2 + * cmpl op1, op2 movl ct, dest + * setcc dest jcc 1f + * decl dest movl cf, dest + * andl (cf-ct),dest 1: + * addl ct,dest + * + * Size 20. Size 14. + * + * This is reasonably steep, but branch mispredict costs are + * high on modern cpus, so consider failing only if optimizing + * for space. + * + * %%% Parameterize branch_cost on the tuning architecture, then + * use that. The 80386 couldn't care less about mispredicts. + */ + + if (!optimize_size && !TARGET_CMOVE) + { + if (ct == 0) + { + ct = cf; + cf = 0; + if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0))) + { + /* We may be reversing unordered compare to normal compare, + that is not valid in general (we may convert non-trapping + condition to trapping one), however on i386 we currently + emit all comparisons unordered. */ + compare_code = reverse_condition_maybe_unordered (compare_code); + code = reverse_condition_maybe_unordered (code); + } + else + { + compare_code = reverse_condition (compare_code); + code = reverse_condition (code); + } + } - /* 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; + out = emit_store_flag (out, code, ix86_compare_op0, + ix86_compare_op1, VOIDmode, 0, 1); + + out = expand_simple_binop (mode, PLUS, + out, constm1_rtx, + out, 1, OPTAB_DIRECT); + out = expand_simple_binop (mode, AND, + out, + GEN_INT (trunc_int_for_mode + (cf - ct, mode)), + out, 1, OPTAB_DIRECT); + out = expand_simple_binop (mode, PLUS, + out, GEN_INT (ct), + out, 1, OPTAB_DIRECT); + if (out != operands[0]) + emit_move_insn (operands[0], out); + + return 1; /* DONE */ + } + } - /* Find the base index and offset elements of the memory address. */ - if (GET_CODE (mem_addr) == PLUS) + if (!TARGET_CMOVE) { - if (GET_CODE (XEXP (mem_addr, 0)) == REG) + /* Try a few things more with specific constants and a variable. */ + + optab op; + rtx var, orig_out, out, tmp; + + if (optimize_size) + return 0; /* FAIL */ + + /* If one of the two operands is an interesting constant, load a + constant with the above and mask it in with a logical operation. */ + + if (GET_CODE (operands[2]) == CONST_INT) { - if (GET_CODE (XEXP (mem_addr, 1)) == REG) - base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0); + var = operands[3]; + if (INTVAL (operands[2]) == 0) + operands[3] = constm1_rtx, op = and_optab; + else if (INTVAL (operands[2]) == -1) + operands[3] = const0_rtx, op = ior_optab; else - base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1); + return 0; /* FAIL */ } - - else if (GET_CODE (XEXP (mem_addr, 0)) == MULT) + else if (GET_CODE (operands[3]) == CONST_INT) { - index_rtx = XEXP (mem_addr, 0); - if (GET_CODE (XEXP (mem_addr, 1)) == REG) - base_rtx = XEXP (mem_addr, 1); + var = operands[2]; + if (INTVAL (operands[3]) == 0) + operands[2] = constm1_rtx, op = and_optab; + else if (INTVAL (operands[3]) == -1) + operands[2] = const0_rtx, op = ior_optab; else - offset_rtx = XEXP (mem_addr, 1); + return 0; /* FAIL */ } + else + return 0; /* FAIL */ + + orig_out = operands[0]; + tmp = gen_reg_rtx (mode); + operands[0] = tmp; + + /* Recurse to get the constant loaded. */ + if (ix86_expand_int_movcc (operands) == 0) + return 0; /* FAIL */ + + /* Mask in the interesting variable. */ + out = expand_binop (mode, op, var, tmp, orig_out, 0, + OPTAB_WIDEN); + if (out != orig_out) + emit_move_insn (orig_out, out); + + return 1; /* DONE */ + } + + /* + * For comparison with above, + * + * movl cf,dest + * movl ct,tmp + * cmpl op1,op2 + * cmovcc tmp,dest + * + * Size 15. + */ + + if (! nonimmediate_operand (operands[2], mode)) + operands[2] = force_reg (mode, operands[2]); + if (! nonimmediate_operand (operands[3], mode)) + operands[3] = force_reg (mode, operands[3]); + + if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3])) + { + rtx tmp = gen_reg_rtx (mode); + emit_move_insn (tmp, operands[3]); + operands[3] = tmp; + } + if (second_test && reg_overlap_mentioned_p (operands[0], operands[2])) + { + rtx tmp = gen_reg_rtx (mode); + emit_move_insn (tmp, operands[2]); + operands[2] = tmp; + } + if (! register_operand (operands[2], VOIDmode) + && ! register_operand (operands[3], VOIDmode)) + operands[2] = force_reg (mode, operands[2]); + + emit_insn (compare_seq); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (mode, + compare_op, operands[2], + operands[3]))); + if (bypass_test) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (mode, + bypass_test, + operands[3], + operands[0]))); + if (second_test) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (mode, + second_test, + operands[2], + operands[0]))); + + return 1; /* DONE */ +} - else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS) +int +ix86_expand_fp_movcc (operands) + rtx operands[]; +{ + enum rtx_code code; + rtx tmp; + rtx compare_op, second_test, bypass_test; + + /* For SF/DFmode conditional moves based on comparisons + in same mode, we may want to use SSE min/max instructions. */ + if (((TARGET_SSE_MATH && GET_MODE (operands[0]) == SFmode) + || (TARGET_SSE2 && TARGET_SSE_MATH && GET_MODE (operands[0]) == DFmode)) + && GET_MODE (ix86_compare_op0) == GET_MODE (operands[0]) + /* The SSE comparisons does not support the LTGT/UNEQ pair. */ + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != LTGT && GET_CODE (operands[1]) != UNEQ)) + /* We may be called from the post-reload splitter. */ + && (!REG_P (operands[0]) + || SSE_REG_P (operands[0]) + || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)) + { + rtx op0 = ix86_compare_op0, op1 = ix86_compare_op1; + code = GET_CODE (operands[1]); + + /* See if we have (cross) match between comparison operands and + conditional move operands. */ + if (rtx_equal_p (operands[2], op1)) + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + code = reverse_condition_maybe_unordered (code); + } + if (rtx_equal_p (operands[2], op0) && rtx_equal_p (operands[3], op1)) { - 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) + /* Check for min operation. */ + if (code == LT) { - 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)); + operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); + if (memory_operand (op0, VOIDmode)) + op0 = force_reg (GET_MODE (operands[0]), op0); + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_minsf3 (operands[0], op0, op1)); + else + emit_insn (gen_mindf3 (operands[0], op0, op1)); + return 1; } - else + /* Check for max operation. */ + if (code == GT) { - offset_rtx = XEXP (mem_addr, 1); - index_rtx = XEXP (XEXP (mem_addr, 0), 0); - base_rtx = XEXP (XEXP (mem_addr, 0), 1); + operands[0] = force_reg (GET_MODE (operands[0]), operands[0]); + if (memory_operand (op0, VOIDmode)) + op0 = force_reg (GET_MODE (operands[0]), op0); + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_maxsf3 (operands[0], op0, op1)); + else + emit_insn (gen_maxdf3 (operands[0], op0, op1)); + return 1; } } - - else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT) + /* Manage condition to be sse_comparison_operator. In case we are + in non-ieee mode, try to canonicalize the destination operand + to be first in the comparison - this helps reload to avoid extra + moves. */ + if (!sse_comparison_operator (operands[1], VOIDmode) + || (rtx_equal_p (operands[0], ix86_compare_op1) && !TARGET_IEEE_FP)) { - 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; - } + rtx tmp = ix86_compare_op0; + ix86_compare_op0 = ix86_compare_op1; + ix86_compare_op1 = tmp; + operands[1] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), + VOIDmode, ix86_compare_op0, + ix86_compare_op1); } - else + /* Similary try to manage result to be first operand of conditional + move. We also don't support the NE comparison on SSE, so try to + avoid it. */ + if ((rtx_equal_p (operands[0], operands[3]) + && (!TARGET_IEEE_FP || GET_CODE (operands[1]) != EQ)) + || (GET_CODE (operands[1]) == NE && TARGET_IEEE_FP)) { - obfree (storage); - return; + rtx tmp = operands[2]; + operands[2] = operands[3]; + operands[3] = tmp; + operands[1] = gen_rtx_fmt_ee (reverse_condition_maybe_unordered + (GET_CODE (operands[1])), + VOIDmode, ix86_compare_op0, + ix86_compare_op1); } + if (GET_MODE (operands[0]) == SFmode) + emit_insn (gen_sse_movsfcc (operands[0], operands[1], + operands[2], operands[3], + ix86_compare_op0, ix86_compare_op1)); + else + emit_insn (gen_sse_movdfcc (operands[0], operands[1], + operands[2], operands[3], + ix86_compare_op0, ix86_compare_op1)); + return 1; } - else if (GET_CODE (mem_addr) == MULT) - index_rtx = mem_addr; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + code = GET_CODE (operands[1]); + compare_op = ix86_expand_compare (code, &second_test, &bypass_test); + + /* The floating point conditional move instructions don't directly + support signed integer comparisons. */ + + if (!fcmov_comparison_operator (compare_op, VOIDmode)) + { + if (second_test != NULL || bypass_test != NULL) + abort (); + tmp = gen_reg_rtx (QImode); + ix86_expand_setcc (code, tmp); + code = NE; + ix86_compare_op0 = tmp; + ix86_compare_op1 = const0_rtx; + compare_op = ix86_expand_compare (code, &second_test, &bypass_test); + } + if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3])) + { + tmp = gen_reg_rtx (GET_MODE (operands[0])); + emit_move_insn (tmp, operands[3]); + operands[3] = tmp; + } + if (second_test && reg_overlap_mentioned_p (operands[0], operands[2])) + { + tmp = gen_reg_rtx (GET_MODE (operands[0])); + emit_move_insn (tmp, operands[2]); + operands[2] = tmp; + } + + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + compare_op, + operands[2], + operands[3]))); + if (bypass_test) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + bypass_test, + operands[3], + operands[0]))); + if (second_test) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), + second_test, + operands[2], + operands[0]))); + + return 1; +} + +/* Split operands 0 and 1 into SImode parts. Similar to split_di, but + works for floating pointer parameters and nonoffsetable memories. + For pushes, it returns just stack offsets; the values will be saved + in the right order. Maximally three parts are generated. */ + +static int +ix86_split_to_parts (operand, parts, mode) + rtx operand; + rtx *parts; + enum machine_mode mode; +{ + int size; + + if (!TARGET_64BIT) + size = mode == TFmode ? 3 : (GET_MODE_SIZE (mode) / 4); else + size = (GET_MODE_SIZE (mode) + 4) / 8; + + if (GET_CODE (operand) == REG && MMX_REGNO_P (REGNO (operand))) + abort (); + if (size < 2 || size > 3) + abort (); + + /* Optimize constant pool reference to immediates. This is used by fp moves, + that force all constants to memory to allow combining. */ + + if (GET_CODE (operand) == MEM + && GET_CODE (XEXP (operand, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (operand, 0))) + operand = get_pool_constant (XEXP (operand, 0)); + + if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand)) { - obfree (storage); - return; - } + /* The only non-offsetable memories we handle are pushes. */ + if (! push_operand (operand, VOIDmode)) + abort (); - if (index_rtx != 0 && GET_CODE (index_rtx) == MULT) + operand = copy_rtx (operand); + PUT_MODE (operand, Pmode); + parts[0] = parts[1] = parts[2] = operand; + } + else if (!TARGET_64BIT) { - if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT) + if (mode == DImode) + split_di (&operand, 1, &parts[0], &parts[1]); + else { - obfree (storage); - return; + if (REG_P (operand)) + { + if (!reload_completed) + abort (); + parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0); + parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1); + if (size == 3) + parts[2] = gen_rtx_REG (SImode, REGNO (operand) + 2); + } + else if (offsettable_memref_p (operand)) + { + operand = adjust_address (operand, SImode, 0); + parts[0] = operand; + parts[1] = adjust_address (operand, SImode, 4); + if (size == 3) + parts[2] = adjust_address (operand, SImode, 8); + } + else if (GET_CODE (operand) == CONST_DOUBLE) + { + REAL_VALUE_TYPE r; + long l[4]; + + REAL_VALUE_FROM_CONST_DOUBLE (r, operand); + switch (mode) + { + case XFmode: + case TFmode: + REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); + parts[2] = GEN_INT (trunc_int_for_mode (l[2], SImode)); + break; + case DFmode: + REAL_VALUE_TO_TARGET_DOUBLE (r, l); + break; + default: + abort (); + } + parts[1] = GEN_INT (trunc_int_for_mode (l[1], SImode)); + parts[0] = GEN_INT (trunc_int_for_mode (l[0], SImode)); + } + else + abort (); } + } + else + { + if (mode == TImode) + split_ti (&operand, 1, &parts[0], &parts[1]); + if (mode == XFmode || mode == TFmode) + { + if (REG_P (operand)) + { + if (!reload_completed) + abort (); + parts[0] = gen_rtx_REG (DImode, REGNO (operand) + 0); + parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1); + } + else if (offsettable_memref_p (operand)) + { + operand = adjust_address (operand, DImode, 0); + parts[0] = operand; + parts[1] = adjust_address (operand, SImode, 8); + } + else if (GET_CODE (operand) == CONST_DOUBLE) + { + REAL_VALUE_TYPE r; + long l[3]; - scale_rtx = XEXP (index_rtx, 1); - scale = INTVAL (scale_rtx); - index_rtx = copy_all_rtx (XEXP (index_rtx, 0)); + REAL_VALUE_FROM_CONST_DOUBLE (r, operand); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); + /* Do not use shift by 32 to avoid warning on 32bit systems. */ + if (HOST_BITS_PER_WIDE_INT >= 64) + parts[0] + = GEN_INT (trunc_int_for_mode + ((l[0] & (((HOST_WIDE_INT) 2 << 31) - 1)) + + ((((HOST_WIDE_INT) l[1]) << 31) << 1), + DImode)); + else + parts[0] = immed_double_const (l[0], l[1], DImode); + parts[1] = GEN_INT (trunc_int_for_mode (l[2], SImode)); + } + else + abort (); + } } - /* 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; + return size; +} + +/* Emit insns to perform a move or push of DI, DF, and XF values. + Return false when normal moves are needed; true when all required + insns have been emitted. Operands 2-4 contain the input values + int the correct order; operands 5-7 contain the output values. */ + +void +ix86_split_long_move (operands) + rtx operands[]; +{ + rtx part[2][3]; + int nparts; + int push = 0; + int collisions = 0; + enum machine_mode mode = GET_MODE (operands[0]); - 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; + /* The DFmode expanders may ask us to move double. + For 64bit target this is single move. By hiding the fact + here we simplify i386.md splitters. */ + if (GET_MODE_SIZE (GET_MODE (operands[0])) == 8 && TARGET_64BIT) + { + /* Optimize constant pool reference to immediates. This is used by + fp moves, that force all constants to memory to allow combining. */ - RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx; - XEXP (mem_rtx, 0) = offset_rtx; + if (GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))) + operands[1] = get_pool_constant (XEXP (operands[1], 0)); + if (push_operand (operands[0], VOIDmode)) + { + operands[0] = copy_rtx (operands[0]); + PUT_MODE (operands[0], Pmode); + } + else + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, operands[1]); + emit_move_insn (operands[0], operands[1]); return; } - if (base_rtx && GET_CODE (base_rtx) == PLUS - && GET_CODE (XEXP (base_rtx, 0)) == REG - && GET_CODE (XEXP (base_rtx, 1)) == CONST_INT) + /* The only non-offsettable memory we handle is push. */ + if (push_operand (operands[0], VOIDmode)) + push = 1; + else if (GET_CODE (operands[0]) == MEM + && ! offsettable_memref_p (operands[0])) + abort (); + + nparts = ix86_split_to_parts (operands[1], part[1], GET_MODE (operands[0])); + ix86_split_to_parts (operands[0], part[0], GET_MODE (operands[0])); + + /* When emitting push, take care for source operands on the stack. */ + if (push && GET_CODE (operands[1]) == MEM + && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) { - offset_adjust += INTVAL (XEXP (base_rtx, 1)); - base_rtx = copy_all_rtx (XEXP (base_rtx, 0)); + if (nparts == 3) + part[1][1] = change_address (part[1][1], GET_MODE (part[1][1]), + XEXP (part[1][2], 0)); + part[1][0] = change_address (part[1][0], GET_MODE (part[1][0]), + XEXP (part[1][1], 0)); } - else if (base_rtx && GET_CODE (base_rtx) == CONST_INT) + /* We need to do copy in the right order in case an address register + of the source overlaps the destination. */ + if (REG_P (part[0][0]) && GET_CODE (part[1][0]) == MEM) { - offset_adjust += INTVAL (base_rtx); - base_rtx = NULL; + if (reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))) + collisions++; + if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0))) + collisions++; + if (nparts == 3 + && reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0))) + collisions++; + + /* Collision in the middle part can be handled by reordering. */ + if (collisions == 1 && nparts == 3 + && reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0))) + { + rtx tmp; + tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp; + tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp; + } + + /* If there are more collisions, we can't handle it by reordering. + Do an lea to the last part and use only one colliding move. */ + else if (collisions > 1) + { + collisions = 1; + emit_insn (gen_rtx_SET (VOIDmode, part[0][nparts - 1], + XEXP (part[1][0], 0))); + part[1][0] = change_address (part[1][0], + TARGET_64BIT ? DImode : SImode, + part[0][nparts - 1]); + part[1][1] = adjust_address (part[1][0], VOIDmode, UNITS_PER_WORD); + if (nparts == 3) + part[1][2] = adjust_address (part[1][0], VOIDmode, 8); + } } - if (index_rtx && GET_CODE (index_rtx) == PLUS - && GET_CODE (XEXP (index_rtx, 0)) == REG - && GET_CODE (XEXP (index_rtx, 1)) == CONST_INT) + if (push) { - offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale; - index_rtx = copy_all_rtx (XEXP (index_rtx, 0)); + if (!TARGET_64BIT) + { + if (nparts == 3) + { + /* We use only first 12 bytes of TFmode value, but for pushing we + are required to adjust stack as if we were pushing real 16byte + value. */ + if (mode == TFmode && !TARGET_64BIT) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (-4))); + emit_move_insn (part[0][2], part[1][2]); + } + } + else + { + /* In 64bit mode we don't have 32bit push available. In case this is + register, it is OK - we will just use larger counterpart. We also + retype memory - these comes from attempt to avoid REX prefix on + moving of second half of TFmode value. */ + if (GET_MODE (part[1][1]) == SImode) + { + if (GET_CODE (part[1][1]) == MEM) + part[1][1] = adjust_address (part[1][1], DImode, 0); + else if (REG_P (part[1][1])) + part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1])); + else + abort (); + if (GET_MODE (part[1][0]) == SImode) + part[1][0] = part[1][1]; + } + } + emit_move_insn (part[0][1], part[1][1]); + emit_move_insn (part[0][0], part[1][0]); + return; } - if (index_rtx) + /* Choose correct order to not overwrite the source before it is copied. */ + if ((REG_P (part[0][0]) + && REG_P (part[1][1]) + && (REGNO (part[0][0]) == REGNO (part[1][1]) + || (nparts == 3 + && REGNO (part[0][0]) == REGNO (part[1][2])))) + || (collisions > 0 + && reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0)))) { - if (! LEGITIMATE_INDEX_P (index_rtx) - && ! (index_rtx == stack_pointer_rtx && scale == 1 - && base_rtx == NULL)) + if (nparts == 3) { - obfree (storage); - return; + operands[2] = part[0][2]; + operands[3] = part[0][1]; + operands[4] = part[0][0]; + operands[5] = part[1][2]; + operands[6] = part[1][1]; + operands[7] = part[1][0]; + } + else + { + operands[2] = part[0][1]; + operands[3] = part[0][0]; + operands[5] = part[1][1]; + operands[6] = part[1][0]; } } - - if (base_rtx) + else { - if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG) + if (nparts == 3) { - obfree (storage); - return; + operands[2] = part[0][0]; + operands[3] = part[0][1]; + operands[4] = part[0][2]; + operands[5] = part[1][0]; + operands[6] = part[1][1]; + operands[7] = part[1][2]; + } + else + { + operands[2] = part[0][0]; + operands[3] = part[0][1]; + operands[5] = part[1][0]; + operands[6] = part[1][1]; } } + emit_move_insn (operands[2], operands[5]); + emit_move_insn (operands[3], operands[6]); + if (nparts == 3) + emit_move_insn (operands[4], operands[7]); + + return; +} + +void +ix86_split_ashldi (operands, scratch) + rtx *operands, scratch; +{ + rtx low[2], high[2]; + int count; - if (offset_adjust != 0) + if (GET_CODE (operands[2]) == CONST_INT) { - if (offset_rtx != 0 && CONSTANT_P (offset_rtx)) - offset_rtx = plus_constant (offset_rtx, offset_adjust); - else - offset_rtx = const0_rtx; + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - if (index_rtx) + if (count >= 32) { - 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); + emit_move_insn (high[0], low[1]); + emit_move_insn (low[0], const0_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); - } - } + if (count > 32) + emit_insn (gen_ashlsi3 (high[0], high[0], GEN_INT (count - 32))); } 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; - } + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_x86_shld_1 (high[0], low[0], GEN_INT (count))); + emit_insn (gen_ashlsi3 (low[0], low[0], GEN_INT (count))); } - - XEXP (mem_rtx, 0) = ret_rtx; - RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx; - return; } else { - obfree (storage); - return; + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); + + split_di (operands, 1, low, high); + + emit_insn (gen_x86_shld_1 (high[0], low[0], operands[2])); + emit_insn (gen_ashlsi3 (low[0], low[0], operands[2])); + + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) + { + if (! no_new_pseudos) + scratch = force_reg (SImode, const0_rtx); + else + emit_move_insn (scratch, const0_rtx); + + emit_insn (gen_x86_shift_adj_1 (high[0], low[0], operands[2], + scratch)); + } + else + emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2])); } } -#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; + +void +ix86_split_ashrdi (operands, scratch) + rtx *operands, scratch; { - rtx prev_insn = PREV_INSN (insn); + rtx low[2], high[2]; + int count; - while (prev_insn) + if (GET_CODE (operands[2]) == CONST_INT) { - if (GET_CODE (prev_insn) == NOTE) - ; + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - else if (GET_CODE (prev_insn) == INSN) + if (count >= 32) { - if (GET_CODE (PATTERN (prev_insn)) != SET) - return (0); + emit_move_insn (low[0], high[1]); - if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx)) + if (! reload_completed) + emit_insn (gen_ashrsi3 (high[0], low[0], GEN_INT (31))); + else { - if (sets_condition_code (SET_SRC (PATTERN (prev_insn)))) - return (1); - - return (0); + emit_move_insn (high[0], low[0]); + emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (31))); } - else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn)))) - return (0); + if (count > 32) + emit_insn (gen_ashrsi3 (low[0], low[0], GEN_INT (count - 32))); } - else - return (0); - - prev_insn = PREV_INSN (prev_insn); + { + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); + emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (count))); + } } + else + { + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); - return (0); + split_di (operands, 1, low, high); + + emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); + emit_insn (gen_ashrsi3 (high[0], high[0], operands[2])); + + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) + { + if (! no_new_pseudos) + scratch = gen_reg_rtx (SImode); + emit_move_insn (scratch, high[0]); + emit_insn (gen_ashrsi3 (scratch, scratch, GEN_INT (31))); + emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], + scratch)); + } + else + emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2])); + } } - -int -doesnt_set_condition_code (pat) - rtx pat; + +void +ix86_split_lshrdi (operands, scratch) + rtx *operands, scratch; { - switch (GET_CODE (pat)) + rtx low[2], high[2]; + int count; + + if (GET_CODE (operands[2]) == CONST_INT) { - case MEM: - case REG: - return 1; + split_di (operands, 2, low, high); + count = INTVAL (operands[2]) & 63; - default: - return 0; + if (count >= 32) + { + emit_move_insn (low[0], high[1]); + emit_move_insn (high[0], const0_rtx); + if (count > 32) + emit_insn (gen_lshrsi3 (low[0], low[0], GEN_INT (count - 32))); + } + else + { + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); + emit_insn (gen_lshrsi3 (high[0], high[0], GEN_INT (count))); + } } -} - -int -sets_condition_code (pat) - rtx pat; -{ - switch (GET_CODE (pat)) + else { - 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; + if (!rtx_equal_p (operands[0], operands[1])) + emit_move_insn (operands[0], operands[1]); - default: - return (0); + split_di (operands, 1, low, high); + + emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); + emit_insn (gen_lshrsi3 (high[0], high[0], operands[2])); + + /* Heh. By reversing the arguments, we can reuse this pattern. */ + if (TARGET_CMOVE && (! no_new_pseudos || scratch)) + { + if (! no_new_pseudos) + scratch = force_reg (SImode, const0_rtx); + else + emit_move_insn (scratch, const0_rtx); + + emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], + scratch)); + } + else + emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2])); } } - -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; +/* Helper function for the string operations below. Dest VARIABLE whether + it is aligned to VALUE bytes. If true, jump to the label. */ +static rtx +ix86_expand_aligntest (variable, value) + rtx variable; + int value; { - 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; + rtx label = gen_label_rtx (); + rtx tmpcount = gen_reg_rtx (GET_MODE (variable)); + if (GET_MODE (variable) == DImode) + emit_insn (gen_anddi3 (tmpcount, variable, GEN_INT (value))); + else + emit_insn (gen_andsi3 (tmpcount, variable, GEN_INT (value))); + emit_cmp_and_jump_insns (tmpcount, const0_rtx, EQ, 0, GET_MODE (variable), + 1, label); + return label; +} - return 0; +/* Adjust COUNTER by the VALUE. */ +static void +ix86_adjust_counter (countreg, value) + rtx countreg; + HOST_WIDE_INT value; +{ + if (GET_MODE (countreg) == DImode) + emit_insn (gen_adddi3 (countreg, countreg, GEN_INT (-value))); + else + emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-value))); } -/* 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 */ +/* Zero extend possibly SImode EXP to Pmode register. */ +rtx +ix86_zero_extend_to_Pmode (exp) + rtx exp; +{ + rtx r; + if (GET_MODE (exp) == VOIDmode) + return force_reg (Pmode, exp); + if (GET_MODE (exp) == Pmode) + return copy_to_mode_reg (Pmode, exp); + r = gen_reg_rtx (Pmode); + emit_insn (gen_zero_extendsidi2 (r, exp)); + return r; +} +/* Expand string move (memcpy) operation. Use i386 string operations when + profitable. expand_clrstr contains similar code. */ int -is_fp_dest (insn) - rtx insn; +ix86_expand_movstr (dst, src, count_exp, align_exp) + rtx dst, src, count_exp, align_exp; { - 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; + rtx srcreg, destreg, countreg; + enum machine_mode counter_mode; + HOST_WIDE_INT align = 0; + unsigned HOST_WIDE_INT count = 0; + rtx insns; + + start_sequence (); + + if (GET_CODE (align_exp) == CONST_INT) + align = INTVAL (align_exp); + + /* This simple hack avoids all inlining code and simplifies code below. */ + if (!TARGET_ALIGN_STRINGOPS) + align = 64; + + if (GET_CODE (count_exp) == CONST_INT) + count = INTVAL (count_exp); + + /* Figure out proper mode for counter. For 32bits it is always SImode, + for 64bits use SImode when possible, otherwise DImode. + Set count to number of bytes copied when known at compile time. */ + if (!TARGET_64BIT || GET_MODE (count_exp) == SImode + || x86_64_zero_extended_value (count_exp)) + counter_mode = SImode; + else + counter_mode = DImode; - return 0; -} + if (counter_mode != SImode && counter_mode != DImode) + abort (); -/* Return 1 if the mode of the SET_DEST of INSN is floating point and is - memory and the source is a register. */ + destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0)); + srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0)); -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; + emit_insn (gen_cld ()); - return 0; + /* When optimizing for size emit simple rep ; movsb instruction for + counts not divisible by 4. */ + + if ((!optimize || optimize_size) && (count == 0 || (count & 0x03))) + { + countreg = ix86_zero_extend_to_Pmode (count_exp); + if (TARGET_64BIT) + emit_insn (gen_rep_movqi_rex64 (destreg, srcreg, countreg, + destreg, srcreg, countreg)); + else + emit_insn (gen_rep_movqi (destreg, srcreg, countreg, + destreg, srcreg, countreg)); + } + + /* For constant aligned (or small unaligned) copies use rep movsl + followed by code copying the rest. For PentiumPro ensure 8 byte + alignment to allow rep movsl acceleration. */ + + else if (count != 0 + && (align >= 8 + || (!TARGET_PENTIUMPRO && !TARGET_64BIT && align >= 4) + || optimize_size || count < (unsigned int) 64)) + { + int size = TARGET_64BIT && !optimize_size ? 8 : 4; + if (count & ~(size - 1)) + { + countreg = copy_to_mode_reg (counter_mode, + GEN_INT ((count >> (size == 4 ? 2 : 3)) + & (TARGET_64BIT ? -1 : 0x3fffffff))); + countreg = ix86_zero_extend_to_Pmode (countreg); + if (size == 4) + { + if (TARGET_64BIT) + emit_insn (gen_rep_movsi_rex64 (destreg, srcreg, countreg, + destreg, srcreg, countreg)); + else + emit_insn (gen_rep_movsi (destreg, srcreg, countreg, + destreg, srcreg, countreg)); + } + else + emit_insn (gen_rep_movdi_rex64 (destreg, srcreg, countreg, + destreg, srcreg, countreg)); + } + if (size == 8 && (count & 0x04)) + emit_insn (gen_strmovsi (destreg, srcreg)); + if (count & 0x02) + emit_insn (gen_strmovhi (destreg, srcreg)); + if (count & 0x01) + emit_insn (gen_strmovqi (destreg, srcreg)); + } + /* The generic code based on the glibc implementation: + - align destination to 4 bytes (8 byte alignment is used for PentiumPro + allowing accelerated copying there) + - copy the data using rep movsl + - copy the rest. */ + else + { + rtx countreg2; + rtx label = NULL; + + /* In case we don't know anything about the alignment, default to + library version, since it is usually equally fast and result in + shorter code. */ + if (!TARGET_INLINE_ALL_STRINGOPS && align < UNITS_PER_WORD) + { + end_sequence (); + return 0; + } + + if (TARGET_SINGLE_STRINGOP) + emit_insn (gen_cld ()); + + countreg2 = gen_reg_rtx (Pmode); + countreg = copy_to_mode_reg (counter_mode, count_exp); + + /* We don't use loops to align destination and to copy parts smaller + than 4 bytes, because gcc is able to optimize such code better (in + the case the destination or the count really is aligned, gcc is often + able to predict the branches) and also it is friendlier to the + hardware branch prediction. + + Using loops is benefical for generic case, because we can + handle small counts using the loops. Many CPUs (such as Athlon) + have large REP prefix setup costs. + + This is quite costy. Maybe we can revisit this decision later or + add some customizability to this code. */ + + if (count == 0 + && align < (TARGET_PENTIUMPRO && (count == 0 + || count >= (unsigned int) 260) + ? 8 : UNITS_PER_WORD)) + { + label = gen_label_rtx (); + emit_cmp_and_jump_insns (countreg, GEN_INT (UNITS_PER_WORD - 1), + LEU, 0, counter_mode, 1, label); + } + if (align <= 1) + { + rtx label = ix86_expand_aligntest (destreg, 1); + emit_insn (gen_strmovqi (destreg, srcreg)); + ix86_adjust_counter (countreg, 1); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align <= 2) + { + rtx label = ix86_expand_aligntest (destreg, 2); + emit_insn (gen_strmovhi (destreg, srcreg)); + ix86_adjust_counter (countreg, 2); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align <= 4 + && ((TARGET_PENTIUMPRO && (count == 0 + || count >= (unsigned int) 260)) + || TARGET_64BIT)) + { + rtx label = ix86_expand_aligntest (destreg, 4); + emit_insn (gen_strmovsi (destreg, srcreg)); + ix86_adjust_counter (countreg, 4); + emit_label (label); + LABEL_NUSES (label) = 1; + } + + if (!TARGET_SINGLE_STRINGOP) + emit_insn (gen_cld ()); + if (TARGET_64BIT) + { + emit_insn (gen_lshrdi3 (countreg2, ix86_zero_extend_to_Pmode (countreg), + GEN_INT (3))); + emit_insn (gen_rep_movdi_rex64 (destreg, srcreg, countreg2, + destreg, srcreg, countreg2)); + } + else + { + emit_insn (gen_lshrsi3 (countreg2, countreg, GEN_INT (2))); + emit_insn (gen_rep_movsi (destreg, srcreg, countreg2, + destreg, srcreg, countreg2)); + } + + if (label) + { + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (TARGET_64BIT && align > 4 && count != 0 && (count & 4)) + emit_insn (gen_strmovsi (destreg, srcreg)); + if ((align <= 4 || count == 0) && TARGET_64BIT) + { + rtx label = ix86_expand_aligntest (countreg, 4); + emit_insn (gen_strmovsi (destreg, srcreg)); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align > 2 && count != 0 && (count & 2)) + emit_insn (gen_strmovhi (destreg, srcreg)); + if (align <= 2 || count == 0) + { + rtx label = ix86_expand_aligntest (countreg, 2); + emit_insn (gen_strmovhi (destreg, srcreg)); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align > 1 && count != 0 && (count & 1)) + emit_insn (gen_strmovqi (destreg, srcreg)); + if (align <= 1 || count == 0) + { + rtx label = ix86_expand_aligntest (countreg, 1); + emit_insn (gen_strmovqi (destreg, srcreg)); + emit_label (label); + LABEL_NUSES (label) = 1; + } + } + + insns = get_insns (); + end_sequence (); + + ix86_set_move_mem_attrs (insns, dst, src, destreg, srcreg); + emit_insns (insns); + return 1; } - -/* Return 1 if DEP_INSN sets a register which INSN uses as a base - or index to reference memory. - otherwise return 0 */ +/* Expand string clear operation (bzero). Use i386 string operations when + profitable. expand_movstr contains similar code. */ int -agi_dependent (insn, dep_insn) - rtx insn, dep_insn; +ix86_expand_clrstr (src, count_exp, align_exp) + rtx src, count_exp, align_exp; { - 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; + rtx destreg, zeroreg, countreg; + enum machine_mode counter_mode; + HOST_WIDE_INT align = 0; + unsigned HOST_WIDE_INT count = 0; + + if (GET_CODE (align_exp) == CONST_INT) + align = INTVAL (align_exp); + + /* This simple hack avoids all inlining code and simplifies code below. */ + if (!TARGET_ALIGN_STRINGOPS) + align = 32; + + if (GET_CODE (count_exp) == CONST_INT) + count = INTVAL (count_exp); + /* Figure out proper mode for counter. For 32bits it is always SImode, + for 64bits use SImode when possible, otherwise DImode. + Set count to number of bytes copied when known at compile time. */ + if (!TARGET_64BIT || GET_MODE (count_exp) == SImode + || x86_64_zero_extended_value (count_exp)) + counter_mode = SImode; + else + counter_mode = DImode; - 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; + destreg = copy_to_mode_reg (Pmode, XEXP (src, 0)); - 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; + emit_insn (gen_cld ()); - /* CPUs contain special hardware to allow two pushes. */ - if (push && push_dep) - return 0; + /* When optimizing for size emit simple rep ; movsb instruction for + counts not divisible by 4. */ - /* Push operation implicitly change stack pointer causing AGI stalls. */ - if (push_dep && reg_mentioned_in_mem (stack_pointer_rtx, insn)) - return 1; + if ((!optimize || optimize_size) && (count == 0 || (count & 0x03))) + { + countreg = ix86_zero_extend_to_Pmode (count_exp); + zeroreg = copy_to_mode_reg (QImode, const0_rtx); + if (TARGET_64BIT) + emit_insn (gen_rep_stosqi_rex64 (destreg, countreg, zeroreg, + destreg, countreg)); + else + emit_insn (gen_rep_stosqi (destreg, countreg, zeroreg, + destreg, countreg)); + } + else if (count != 0 + && (align >= 8 + || (!TARGET_PENTIUMPRO && !TARGET_64BIT && align >= 4) + || optimize_size || count < (unsigned int) 64)) + { + int size = TARGET_64BIT && !optimize_size ? 8 : 4; + zeroreg = copy_to_mode_reg (size == 4 ? SImode : DImode, const0_rtx); + if (count & ~(size - 1)) + { + countreg = copy_to_mode_reg (counter_mode, + GEN_INT ((count >> (size == 4 ? 2 : 3)) + & (TARGET_64BIT ? -1 : 0x3fffffff))); + countreg = ix86_zero_extend_to_Pmode (countreg); + if (size == 4) + { + if (TARGET_64BIT) + emit_insn (gen_rep_stossi_rex64 (destreg, countreg, zeroreg, + destreg, countreg)); + else + emit_insn (gen_rep_stossi (destreg, countreg, zeroreg, + destreg, countreg)); + } + else + emit_insn (gen_rep_stosdi_rex64 (destreg, countreg, zeroreg, + destreg, countreg)); + } + if (size == 8 && (count & 0x04)) + emit_insn (gen_strsetsi (destreg, + gen_rtx_SUBREG (SImode, zeroreg, 0))); + if (count & 0x02) + emit_insn (gen_strsethi (destreg, + gen_rtx_SUBREG (HImode, zeroreg, 0))); + if (count & 0x01) + emit_insn (gen_strsetqi (destreg, + gen_rtx_SUBREG (QImode, zeroreg, 0))); + } + else + { + rtx countreg2; + rtx label = NULL; - /* Push also implicitly read stack pointer. */ - if (push && modified_in_p (stack_pointer_rtx, dep_insn)) - return 1; + /* In case we don't know anything about the alignment, default to + library version, since it is usually equally fast and result in + shorter code. */ + if (!TARGET_INLINE_ALL_STRINGOPS && align < UNITS_PER_WORD) + return 0; - return 0; -} - -/* Return 1 if reg is used in rtl as a base or index for a memory ref - otherwise return 0. */ + if (TARGET_SINGLE_STRINGOP) + emit_insn (gen_cld ()); + countreg2 = gen_reg_rtx (Pmode); + countreg = copy_to_mode_reg (counter_mode, count_exp); + zeroreg = copy_to_mode_reg (Pmode, const0_rtx); + + if (count == 0 + && align < (TARGET_PENTIUMPRO && (count == 0 + || count >= (unsigned int) 260) + ? 8 : UNITS_PER_WORD)) + { + label = gen_label_rtx (); + emit_cmp_and_jump_insns (countreg, GEN_INT (UNITS_PER_WORD - 1), + LEU, 0, counter_mode, 1, label); + } + if (align <= 1) + { + rtx label = ix86_expand_aligntest (destreg, 1); + emit_insn (gen_strsetqi (destreg, + gen_rtx_SUBREG (QImode, zeroreg, 0))); + ix86_adjust_counter (countreg, 1); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align <= 2) + { + rtx label = ix86_expand_aligntest (destreg, 2); + emit_insn (gen_strsethi (destreg, + gen_rtx_SUBREG (HImode, zeroreg, 0))); + ix86_adjust_counter (countreg, 2); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align <= 4 && TARGET_PENTIUMPRO && (count == 0 + || count >= (unsigned int) 260)) + { + rtx label = ix86_expand_aligntest (destreg, 4); + emit_insn (gen_strsetsi (destreg, (TARGET_64BIT + ? gen_rtx_SUBREG (SImode, zeroreg, 0) + : zeroreg))); + ix86_adjust_counter (countreg, 4); + emit_label (label); + LABEL_NUSES (label) = 1; + } + + if (!TARGET_SINGLE_STRINGOP) + emit_insn (gen_cld ()); + if (TARGET_64BIT) + { + emit_insn (gen_lshrdi3 (countreg2, ix86_zero_extend_to_Pmode (countreg), + GEN_INT (3))); + emit_insn (gen_rep_stosdi_rex64 (destreg, countreg2, zeroreg, + destreg, countreg2)); + } + else + { + emit_insn (gen_lshrsi3 (countreg2, countreg, GEN_INT (2))); + emit_insn (gen_rep_stossi (destreg, countreg2, zeroreg, + destreg, countreg2)); + } + + if (label) + { + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (TARGET_64BIT && align > 4 && count != 0 && (count & 4)) + emit_insn (gen_strsetsi (destreg, + gen_rtx_SUBREG (SImode, zeroreg, 0))); + if (TARGET_64BIT && (align <= 4 || count == 0)) + { + rtx label = ix86_expand_aligntest (destreg, 2); + emit_insn (gen_strsetsi (destreg, + gen_rtx_SUBREG (SImode, zeroreg, 0))); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align > 2 && count != 0 && (count & 2)) + emit_insn (gen_strsethi (destreg, + gen_rtx_SUBREG (HImode, zeroreg, 0))); + if (align <= 2 || count == 0) + { + rtx label = ix86_expand_aligntest (destreg, 2); + emit_insn (gen_strsethi (destreg, + gen_rtx_SUBREG (HImode, zeroreg, 0))); + emit_label (label); + LABEL_NUSES (label) = 1; + } + if (align > 1 && count != 0 && (count & 1)) + emit_insn (gen_strsetqi (destreg, + gen_rtx_SUBREG (QImode, zeroreg, 0))); + if (align <= 1 || count == 0) + { + rtx label = ix86_expand_aligntest (destreg, 1); + emit_insn (gen_strsetqi (destreg, + gen_rtx_SUBREG (QImode, zeroreg, 0))); + emit_label (label); + LABEL_NUSES (label) = 1; + } + } + return 1; +} +/* Expand strlen. */ int -reg_mentioned_in_mem (reg, rtl) - rtx reg, rtl; +ix86_expand_strlen (out, src, eoschar, align) + rtx out, src, eoschar, align; { - register char *fmt; - register int i, j; - register enum rtx_code code; + rtx addr, scratch1, scratch2, scratch3, scratch4; - if (rtl == NULL) + /* The generic case of strlen expander is long. Avoid it's + expanding unless TARGET_INLINE_ALL_STRINGOPS. */ + + if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1 + && !TARGET_INLINE_ALL_STRINGOPS + && !optimize_size + && (GET_CODE (align) != CONST_INT || INTVAL (align) < 4)) return 0; - code = GET_CODE (rtl); + addr = force_reg (Pmode, XEXP (src, 0)); + scratch1 = gen_reg_rtx (Pmode); - switch (code) + if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1 + && !optimize_size) { - 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; - } + /* 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. */ - if (code == MEM && reg_mentioned_p (reg, rtl)) - return 1; + emit_move_insn (out, addr); + + ix86_expand_strlensi_unroll_1 (out, align); - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + /* strlensi_unroll_1 returns the address of the zero at the end of + the string, like memchr(), so compute the length by subtracting + the start address. */ + if (TARGET_64BIT) + emit_insn (gen_subdi3 (out, out, addr)); + else + emit_insn (gen_subsi3 (out, out, addr)); + } + else { - if (fmt[i] == 'E') + scratch2 = gen_reg_rtx (Pmode); + scratch3 = gen_reg_rtx (Pmode); + scratch4 = force_reg (Pmode, constm1_rtx); + + emit_move_insn (scratch3, addr); + eoschar = force_reg (QImode, eoschar); + + emit_insn (gen_cld ()); + if (TARGET_64BIT) { - for (j = XVECLEN (rtl, i) - 1; j >= 0; j--) - if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j))) - return 1; + emit_insn (gen_strlenqi_rex_1 (scratch1, scratch3, eoschar, + align, scratch4, scratch3)); + emit_insn (gen_one_cmpldi2 (scratch2, scratch1)); + emit_insn (gen_adddi3 (out, scratch2, constm1_rtx)); + } + else + { + emit_insn (gen_strlenqi_1 (scratch1, scratch3, eoschar, + align, scratch4, scratch3)); + emit_insn (gen_one_cmplsi2 (scratch2, scratch1)); + emit_insn (gen_addsi3 (out, scratch2, constm1_rtx)); } - - else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i))) - return 1; } - - return 0; + return 1; } - -/* 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 +/* Expand the appropriate insns for doing strlen if not just doing + repnz; scasb + + out = result, initialized with the start address + align_rtx = alignment of the address. + scratch = 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[]; +static void +ix86_expand_strlensi_unroll_1 (out, align_rtx) + rtx out, align_rtx; { - 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); + int align; + rtx tmp; + rtx align_2_label = NULL_RTX; + rtx align_3_label = NULL_RTX; + rtx align_4_label = gen_label_rtx (); + rtx end_0_label = gen_label_rtx (); + rtx mem; + rtx tmpreg = gen_reg_rtx (SImode); + rtx scratch = gen_reg_rtx (SImode); + + align = 0; + if (GET_CODE (align_rtx) == CONST_INT) + align = INTVAL (align_rtx); /* 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) + if (align < 4) { + rtx scratch1 = gen_reg_rtx (Pmode); + emit_move_insn (scratch1, out); /* Is there a known alignment and is it not 2? */ - if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2) + if (align != 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); + align_3_label = gen_label_rtx (); /* Label when aligned to 3-byte */ + align_2_label = gen_label_rtx (); /* Label when aligned to 2-byte */ + + /* Leave just the 3 lower bits. */ + align_rtx = expand_binop (Pmode, and_optab, scratch1, GEN_INT (3), + NULL_RTX, 0, OPTAB_WIDEN); + + emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL, + Pmode, 1, align_4_label); + emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), EQ, NULL, + Pmode, 1, align_2_label); + emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), GTU, NULL, + Pmode, 1, align_3_label); } 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); + align_rtx = expand_binop (Pmode, and_optab, scratch1, GEN_INT (2), + NULL_RTX, 0, OPTAB_WIDEN); + + emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL, + Pmode, 1, align_4_label); } - xops[13] = gen_rtx_MEM (QImode, xops[0]); + mem = gen_rtx_MEM (QImode, out); - /* 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); + /* Now compare the bytes. */ - /* When zero we reached the end. */ - output_asm_insn (AS1 (je,%l12), xops); + /* Compare the first n unaligned byte on a byte per byte basis. */ + emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, + QImode, 1, end_0_label); - /* Increment the address. */ - output_asm_insn (AS1 (inc%L0,%0), xops); + /* Increment the address. */ + if (TARGET_64BIT) + emit_insn (gen_adddi3 (out, out, const1_rtx)); + else + emit_insn (gen_addsi3 (out, out, const1_rtx)); - /* 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])); - } + /* Not needed with an alignment of 2 */ + if (align != 2) + { + emit_label (align_2_label); - 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); + emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1, + end_0_label); - /* 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%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])); - } + if (TARGET_64BIT) + emit_insn (gen_adddi3 (out, out, const1_rtx)); + else + emit_insn (gen_addsi3 (out, out, const1_rtx)); - output_asm_insn (AS2 (cmp%B13,%2,%13), xops); - } + emit_label (align_3_label); + } - output_asm_insn (AS1 (je,%l12), xops); - output_asm_insn (AS1 (inc%L0,%0), xops); + emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1, + end_0_label); + + if (TARGET_64BIT) + emit_insn (gen_adddi3 (out, out, const1_rtx)); + else + emit_insn (gen_addsi3 (out, out, const1_rtx)); } - /* 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])); + /* 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. */ + emit_label (align_4_label); - xops[13] = gen_rtx_MEM (SImode, xops[0]); - output_asm_insn (AS2 (mov%L1,%13,%1), xops); + mem = gen_rtx_MEM (SImode, out); + emit_move_insn (scratch, mem); + if (TARGET_64BIT) + emit_insn (gen_adddi3 (out, out, GEN_INT (4))); + else + emit_insn (gen_addsi3 (out, out, GEN_INT (4))); + + /* This formula yields a nonzero result iff one of the bytes is zero. + This saves three branches inside loop and many cycles. */ + + emit_insn (gen_addsi3 (tmpreg, scratch, GEN_INT (-0x01010101))); + emit_insn (gen_one_cmplsi2 (scratch, scratch)); + emit_insn (gen_andsi3 (tmpreg, tmpreg, scratch)); + emit_insn (gen_andsi3 (tmpreg, tmpreg, + GEN_INT (trunc_int_for_mode + (0x80808080, SImode)))); + emit_cmp_and_jump_insns (tmpreg, const0_rtx, EQ, 0, SImode, 1, + align_4_label); + + if (TARGET_CMOVE) + { + rtx reg = gen_reg_rtx (SImode); + rtx reg2 = gen_reg_rtx (Pmode); + emit_move_insn (reg, tmpreg); + emit_insn (gen_lshrsi3 (reg, reg, GEN_INT (16))); + + /* If zero is not in the first two bytes, move two bytes forward. */ + emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080))); + tmp = gen_rtx_REG (CCNOmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + emit_insn (gen_rtx_SET (VOIDmode, tmpreg, + gen_rtx_IF_THEN_ELSE (SImode, tmp, + reg, + tmpreg))); + /* Emit lea manually to avoid clobbering of flags. */ + emit_insn (gen_rtx_SET (SImode, reg2, + gen_rtx_PLUS (Pmode, out, GEN_INT (2)))); + + tmp = gen_rtx_REG (CCNOmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + emit_insn (gen_rtx_SET (VOIDmode, out, + gen_rtx_IF_THEN_ELSE (Pmode, tmp, + reg2, + out))); - if (QI_REG_P (xops[1])) + } + else { - /* 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); - } + rtx end_2_label = gen_label_rtx (); + /* Is zero in the first two bytes? */ + + emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080))); + tmp = gen_rtx_REG (CCNOmode, FLAGS_REG); + tmp = gen_rtx_NE (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, end_2_label), + pc_rtx); + tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + JUMP_LABEL (tmp) = end_2_label; - /* Check first byte. */ - output_asm_insn (AS2 (test%B1,%b1,%b1), xops); - output_asm_insn (AS1 (je,%l12), xops); + /* Not in the first two. Move two bytes forward. */ + emit_insn (gen_lshrsi3 (tmpreg, tmpreg, GEN_INT (16))); + if (TARGET_64BIT) + emit_insn (gen_adddi3 (out, out, GEN_INT (2))); + else + emit_insn (gen_addsi3 (out, out, GEN_INT (2))); - /* Check second byte. */ - output_asm_insn (AS2 (test%B1,%h1,%h1), xops); - output_asm_insn (AS1 (je,%l11), xops); + emit_label (end_2_label); - if (TARGET_PENTIUM) - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", - CODE_LABEL_NUMBER (xops[9])); } + /* Avoid branch in fixing the byte. */ + tmpreg = gen_lowpart (QImode, tmpreg); + emit_insn (gen_addqi3_cc (tmpreg, tmpreg, tmpreg)); + if (TARGET_64BIT) + emit_insn (gen_subdi3_carry_rex64 (out, out, GEN_INT (3))); else - { - /* Check first byte. */ - output_asm_insn (AS2 (test%L1,%14,%1), xops); - output_asm_insn (AS1 (je,%l12), xops); + emit_insn (gen_subsi3_carry (out, out, GEN_INT (3))); - /* Check second byte. */ - output_asm_insn (AS2 (test%L1,%15,%1), xops); - output_asm_insn (AS1 (je,%l11), xops); - } + emit_label (end_0_label); +} + +/* Clear stack slot assignments remembered from previous functions. + This is called from INIT_EXPANDERS once before RTL is emitted for each + function. */ + +static void +ix86_init_machine_status (p) + struct function *p; +{ + p->machine = (struct machine_function *) + xcalloc (1, sizeof (struct machine_function)); +} + +/* Mark machine specific bits of P for GC. */ +static void +ix86_mark_machine_status (p) + struct function *p; +{ + struct machine_function *machine = p->machine; + enum machine_mode mode; + int n; - /* Check third byte. */ - output_asm_insn (AS2 (test%L1,%16,%1), xops); - output_asm_insn (AS1 (je,%l10), xops); + if (! machine) + return; - /* 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); + 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++) + ggc_mark_rtx (machine->stack_locals[(int) mode][n]); +} - /* Now generate fixups when the compare stops within a 4-byte word. */ - output_asm_insn (AS2 (sub%L0,%4,%0), xops); +static void +ix86_free_machine_status (p) + struct function *p; +{ + free (p->machine); + p->machine = NULL; +} - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10])); - output_asm_insn (AS1 (inc%L0,%0), xops); +/* Return a MEM corresponding to a stack slot with mode MODE. + Allocate a new slot if necessary. - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11])); - output_asm_insn (AS1 (inc%L0,%0), xops); + 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 (); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12])); + if (ix86_stack_locals[(int) mode][n] == NULL_RTX) + ix86_stack_locals[(int) mode][n] + = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); - return ""; + return ix86_stack_locals[(int) mode][n]; } + +/* Calculate the length of the memory address in the instruction + encoding. Does not include the one-byte modrm, opcode, or prefix. */ -char * -output_fp_conditional_move (which_alternative, operands) - int which_alternative; - rtx operands[]; +static int +memory_address_length (addr) + rtx addr; { - enum rtx_code code = GET_CODE (operands[1]); + struct ix86_address parts; + rtx base, index, disp; + int len; + + if (GET_CODE (addr) == PRE_DEC + || GET_CODE (addr) == POST_INC + || GET_CODE (addr) == PRE_MODIFY + || GET_CODE (addr) == POST_MODIFY) + return 0; - /* This should never happen. */ - if (!(cc_prev_status.flags & CC_IN_80387) - && (code == GT || code == LE || code == GE || code == LT)) + if (! ix86_decompose_address (addr, &parts)) abort (); - switch (which_alternative) + base = parts.base; + index = parts.index; + disp = parts.disp; + len = 0; + + /* Register Indirect. */ + if (base && !index && !disp) { - case 0: - /* r <- cond ? arg : r */ - output_asm_insn (AS2 (fcmov%F1,%2,%0), operands); - break; + /* Special cases: ebp and esp need the two-byte modrm form. */ + if (addr == stack_pointer_rtx + || addr == arg_pointer_rtx + || addr == frame_pointer_rtx + || addr == hard_frame_pointer_rtx) + len = 1; + } - case 1: - /* r <- cond ? r : arg */ - output_asm_insn (AS2 (fcmov%f1,%3,%0), operands); - break; + /* Direct Addressing. */ + else if (disp && !base && !index) + len = 4; - default: - abort (); + else + { + /* Find the length of the displacement constant. */ + 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. */ + if (index) + len += 1; } - return ""; + return len; } -char * -output_int_conditional_move (which_alternative, operands) - int which_alternative; - rtx operands[]; +/* Compute default value for "length_immediate" attribute. When SHORTFORM is set + expect that insn have 8bit immediate alternative. */ +int +ix86_attr_length_immediate_default (insn, shortform) + rtx insn; + int shortform; { - enum rtx_code code = GET_CODE (operands[1]); + int len = 0; + int i; + extract_insn_cached (insn); + for (i = recog_data.n_operands - 1; i >= 0; --i) + if (CONSTANT_P (recog_data.operand[i])) + { + if (len) + abort (); + if (shortform + && GET_CODE (recog_data.operand[i]) == CONST_INT + && CONST_OK_FOR_LETTER_P (INTVAL (recog_data.operand[i]), 'K')) + len = 1; + else + { + switch (get_attr_mode (insn)) + { + case MODE_QI: + len+=1; + break; + case MODE_HI: + len+=2; + break; + case MODE_SI: + len+=4; + break; + /* Immediates for DImode instructions are encoded as 32bit sign extended values. */ + case MODE_DI: + len+=4; + break; + default: + fatal_insn ("unknown insn mode", insn); + } + } + } + return len; +} +/* Compute default value for "length_address" attribute. */ +int +ix86_attr_length_address_default (insn) + rtx insn; +{ + int i; + extract_insn_cached (insn); + for (i = recog_data.n_operands - 1; i >= 0; --i) + if (GET_CODE (recog_data.operand[i]) == MEM) + { + return memory_address_length (XEXP (recog_data.operand[i], 0)); + break; + } + return 0; +} + +/* Return the maximum number of instructions a cpu can issue. */ + +static int +ix86_issue_rate () +{ + switch (ix86_cpu) + { + case PROCESSOR_PENTIUM: + case PROCESSOR_K6: + return 2; - /* This is very tricky. We have to do it right. For a code segement - like: + case PROCESSOR_PENTIUMPRO: + case PROCESSOR_PENTIUM4: + case PROCESSOR_ATHLON: + return 3; - int foo, bar; - .... - foo = foo - x; - if (foo >= 0) - bar = y; + default: + return 1; + } +} - 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; +/* A subroutine of ix86_adjust_cost -- return true iff INSN reads flags set + by DEP_INSN and nothing set by DEP_INSN. */ - switch (which_alternative) +static int +ix86_flags_dependant (insn, dep_insn, insn_type) + rtx insn, dep_insn; + enum attr_type insn_type; +{ + rtx set, set2; + + /* Simplify the test for uninteresting insns. */ + if (insn_type != TYPE_SETCC + && insn_type != TYPE_ICMOV + && insn_type != TYPE_FCMOV + && insn_type != TYPE_IBR) + return 0; + + if ((set = single_set (dep_insn)) != 0) { - case 0: - /* r <- cond ? arg : r */ - output_asm_insn (AS2 (cmov%C1,%2,%0), operands); - break; + set = SET_DEST (set); + set2 = NULL_RTX; + } + else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL + && XVECLEN (PATTERN (dep_insn), 0) == 2 + && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET + && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET) + { + set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0)); + set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0)); + } + else + return 0; - case 1: - /* r <- cond ? r : arg */ - output_asm_insn (AS2 (cmov%c1,%3,%0), operands); - break; + if (GET_CODE (set) != REG || REGNO (set) != FLAGS_REG) + return 0; - default: - abort (); + /* This test is true if the dependent insn reads the flags but + not any other potentially set register. */ + if (!reg_overlap_mentioned_p (set, PATTERN (insn))) + return 0; + + if (set2 && reg_overlap_mentioned_p (set2, PATTERN (insn))) + return 0; + + return 1; +} + +/* A subroutine of ix86_adjust_cost -- return true iff INSN has a memory + address with operands set by DEP_INSN. */ + +static int +ix86_agi_dependant (insn, dep_insn, insn_type) + rtx insn, dep_insn; + enum attr_type insn_type; +{ + rtx addr; + + if (insn_type == TYPE_LEA + && TARGET_PENTIUM) + { + addr = PATTERN (insn); + if (GET_CODE (addr) == SET) + ; + else if (GET_CODE (addr) == PARALLEL + && GET_CODE (XVECEXP (addr, 0, 0)) == SET) + addr = XVECEXP (addr, 0, 0); + else + abort (); + addr = SET_SRC (addr); + } + else + { + int i; + extract_insn_cached (insn); + for (i = recog_data.n_operands - 1; i >= 0; --i) + if (GET_CODE (recog_data.operand[i]) == MEM) + { + addr = XEXP (recog_data.operand[i], 0); + goto found; + } + return 0; + found:; } - return ""; + return modified_in_p (addr, dep_insn); } -int -x86_adjust_cost (insn, link, dep_insn, cost) +static int +ix86_adjust_cost (insn, link, dep_insn, cost) rtx insn, link, dep_insn; int cost; { - rtx next_inst; + enum attr_type insn_type, dep_insn_type; + enum attr_memory memory, dep_memory; + rtx set, set2; + int dep_insn_code_number; - if (GET_CODE (dep_insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) + /* Anti and output depenancies have zero cost on all CPUs. */ + if (REG_NOTE_KIND (link) != 0) 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; /* ??? */ + dep_insn_code_number = recog_memoized (dep_insn); + /* If we can't recognize the insns, we can't really do anything. */ + if (dep_insn_code_number < 0 || recog_memoized (insn) < 0) + return cost; + + insn_type = get_attr_type (insn); + dep_insn_type = get_attr_type (dep_insn); 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; + /* Address Generation Interlock adds a cycle of latency. */ + if (ix86_agi_dependant (insn, dep_insn, insn_type)) + cost += 1; + + /* ??? Compares pair with jump/setcc. */ + if (ix86_flags_dependant (insn, dep_insn, insn_type)) + cost = 0; + + /* Floating point stores require value to be ready one cycle ealier. */ + if (insn_type == TYPE_FMOV + && get_attr_memory (insn) == MEMORY_STORE + && !ix86_agi_dependant (insn, dep_insn, insn_type)) + cost += 1; + break; - if (agi_dependent (insn, dep_insn)) - return cost ? cost + 1 : 2; + case PROCESSOR_PENTIUMPRO: + memory = get_attr_memory (insn); + dep_memory = get_attr_memory (dep_insn); + + /* Since we can't represent delayed latencies of load+operation, + increase the cost here for non-imov insns. */ + if (dep_insn_type != TYPE_IMOV + && dep_insn_type != TYPE_FMOV + && (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH)) + cost += 1; + + /* INT->FP conversion is expensive. */ + if (get_attr_fp_int_src (dep_insn)) + cost += 5; + + /* There is one cycle extra latency between an FP op and a store. */ + if (insn_type == TYPE_FMOV + && (set = single_set (dep_insn)) != NULL_RTX + && (set2 = single_set (insn)) != NULL_RTX + && rtx_equal_p (SET_DEST (set), SET_SRC (set2)) + && GET_CODE (SET_DEST (set2)) == MEM) + cost += 1; + + /* Show ability of reorder buffer to hide latency of load by executing + in parallel with previous instruction in case + previous instruction is not needed to compute the address. */ + if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) + { + /* Claim moves to take one cycle, as core can issue one load + at time and the next load can start cycle later. */ + if (dep_insn_type == TYPE_IMOV + || dep_insn_type == TYPE_FMOV) + cost = 1; + else if (cost > 1) + cost--; + } + break; - 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; + case PROCESSOR_K6: + memory = get_attr_memory (insn); + dep_memory = get_attr_memory (dep_insn); + /* The esp dependency is resolved before the instruction is really + finished. */ + if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP) + && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP)) + return 1; + + /* Since we can't represent delayed latencies of load+operation, + increase the cost here for non-imov insns. */ + if (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH) + cost += (dep_insn_type != TYPE_IMOV) ? 2 : 1; - /* Stores stalls one cycle longer than other insns. */ - if (is_fp_insn (insn) && cost && is_fp_store (dep_insn)) - cost++; + /* INT->FP conversion is expensive. */ + if (get_attr_fp_int_src (dep_insn)) + cost += 5; + + /* Show ability of reorder buffer to hide latency of load by executing + in parallel with previous instruction in case + previous instruction is not needed to compute the address. */ + if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) + { + /* Claim moves to take one cycle, as core can issue one load + at time and the next load can start cycle later. */ + if (dep_insn_type == TYPE_IMOV + || dep_insn_type == TYPE_FMOV) + cost = 1; + else if (cost > 2) + cost -= 2; + else + cost = 1; + } break; - case PROCESSOR_K6: - default: - if (!is_fp_dest (dep_insn)) + + case PROCESSOR_ATHLON: + memory = get_attr_memory (insn); + dep_memory = get_attr_memory (dep_insn); + + if (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH) { - if(!agi_dependent (insn, dep_insn)) - return 0; - if (TARGET_486) - return 2; + if (dep_insn_type == TYPE_IMOV || dep_insn_type == TYPE_FMOV) + cost += 2; + else + cost += 3; + } + /* Show ability of reorder buffer to hide latency of load by executing + in parallel with previous instruction in case + previous instruction is not needed to compute the address. */ + if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH) + && !ix86_agi_dependant (insn, dep_insn, insn_type)) + { + /* Claim moves to take one cycle, as core can issue one load + at time and the next load can start cycle later. */ + if (dep_insn_type == TYPE_IMOV + || dep_insn_type == TYPE_FMOV) + cost = 0; + else if (cost >= 3) + cost -= 3; + else + cost = 0; } - 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; + + default: break; } return cost; } -/* Output assembly code for a left shift. +static union +{ + struct ppro_sched_data + { + rtx decode[3]; + int issued_this_cycle; + } ppro; +} ix86_sched_data; + +static int +ix86_safe_length (insn) + rtx insn; +{ + if (recog_memoized (insn) >= 0) + return get_attr_length (insn); + else + return 128; +} + +static int +ix86_safe_length_prefix (insn) + rtx insn; +{ + if (recog_memoized (insn) >= 0) + return get_attr_length (insn); + else + return 0; +} + +static enum attr_memory +ix86_safe_memory (insn) + rtx insn; +{ + if (recog_memoized (insn) >= 0) + return get_attr_memory (insn); + else + return MEMORY_UNKNOWN; +} - Always use "sal" when shifting a memory operand or for a non constant - shift count. +static enum attr_pent_pair +ix86_safe_pent_pair (insn) + rtx insn; +{ + if (recog_memoized (insn) >= 0) + return get_attr_pent_pair (insn); + else + return PENT_PAIR_NP; +} - 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): +static enum attr_ppro_uops +ix86_safe_ppro_uops (insn) + rtx insn; +{ + if (recog_memoized (insn) >= 0) + return get_attr_ppro_uops (insn); + else + return PPRO_UOPS_MANY; +} - 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. +static void +ix86_dump_ppro_packet (dump) + FILE *dump; +{ + if (ix86_sched_data.ppro.decode[0]) + { + fprintf (dump, "PPRO packet: %d", + INSN_UID (ix86_sched_data.ppro.decode[0])); + if (ix86_sched_data.ppro.decode[1]) + fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[1])); + if (ix86_sched_data.ppro.decode[2]) + fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[2])); + fputc ('\n', dump); + } +} + +/* We're beginning a new block. Initialize data structures as necessary. */ + +static void +ix86_sched_init (dump, sched_verbose, veclen) + FILE *dump ATTRIBUTE_UNUSED; + int sched_verbose ATTRIBUTE_UNUSED; + int veclen ATTRIBUTE_UNUSED; +{ + memset (&ix86_sched_data, 0, sizeof (ix86_sched_data)); +} - 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. */ +/* Shift INSN to SLOT, and shift everything else down. */ -char * -output_ashl (insn, operands) - rtx insn, *operands; +static void +ix86_reorder_insn (insnp, slot) + rtx *insnp, *slot; { - /* Handle case where srcreg != dstreg. */ - if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) + if (insnp != slot) { - if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1) - switch (GET_MODE (operands[0])) + rtx insn = *insnp; + do + insnp[0] = insnp[1]; + while (++insnp != slot); + *insnp = insn; + } +} + +/* Find an instruction with given pairability and minimal amount of cycles + lost by the fact that the CPU waits for both pipelines to finish before + reading next instructions. Also take care that both instructions together + can not exceed 7 bytes. */ + +static rtx * +ix86_pent_find_pair (e_ready, ready, type, first) + rtx *e_ready; + rtx *ready; + enum attr_pent_pair type; + rtx first; +{ + int mincycles, cycles; + enum attr_pent_pair tmp; + enum attr_memory memory; + rtx *insnp, *bestinsnp = NULL; + + if (ix86_safe_length (first) > 7 + ix86_safe_length_prefix (first)) + return NULL; + + memory = ix86_safe_memory (first); + cycles = result_ready_cost (first); + mincycles = INT_MAX; + + for (insnp = e_ready; insnp >= ready && mincycles; --insnp) + if ((tmp = ix86_safe_pent_pair (*insnp)) == type + && ix86_safe_length (*insnp) <= 7 + ix86_safe_length_prefix (*insnp)) + { + enum attr_memory second_memory; + int secondcycles, currentcycles; + + second_memory = ix86_safe_memory (*insnp); + secondcycles = result_ready_cost (*insnp); + currentcycles = abs (cycles - secondcycles); + + if (secondcycles >= 1 && cycles >= 1) { - 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 (); + /* Two read/modify/write instructions together takes two + cycles longer. */ + if (memory == MEMORY_BOTH && second_memory == MEMORY_BOTH) + currentcycles += 2; + + /* Read modify/write instruction followed by read/modify + takes one cycle longer. */ + if (memory == MEMORY_BOTH && second_memory == MEMORY_LOAD + && tmp != PENT_PAIR_UV + && ix86_safe_pent_pair (first) != PENT_PAIR_UV) + currentcycles += 1; } - else - { - CC_STATUS_INIT; + if (currentcycles < mincycles) + bestinsnp = insnp, mincycles = currentcycles; + } - /* 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]; - } + return bestinsnp; +} - /* 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); - } +/* Subroutines of ix86_sched_reorder. */ + +static void +ix86_sched_reorder_pentium (ready, e_ready) + rtx *ready; + rtx *e_ready; +{ + enum attr_pent_pair pair1, pair2; + rtx *insnp; + + /* This wouldn't be necessary if Haifa knew that static insn ordering + is important to which pipe an insn is issued to. So we have to make + some minor rearrangements. */ + + pair1 = ix86_safe_pent_pair (*e_ready); + + /* If the first insn is non-pairable, let it be. */ + if (pair1 == PENT_PAIR_NP) + return; + + pair2 = PENT_PAIR_NP; + insnp = 0; + + /* If the first insn is UV or PV pairable, search for a PU + insn to go with. */ + if (pair1 == PENT_PAIR_UV || pair1 == PENT_PAIR_PV) + { + insnp = ix86_pent_find_pair (e_ready-1, ready, + PENT_PAIR_PU, *e_ready); + if (insnp) + pair2 = PENT_PAIR_PU; + } + + /* If the first insn is PU or UV pairable, search for a PV + insn to go with. */ + if (pair2 == PENT_PAIR_NP + && (pair1 == PENT_PAIR_PU || pair1 == PENT_PAIR_UV)) + { + insnp = ix86_pent_find_pair (e_ready-1, ready, + PENT_PAIR_PV, *e_ready); + if (insnp) + pair2 = PENT_PAIR_PV; + } + + /* If the first insn is pairable, search for a UV + insn to go with. */ + if (pair2 == PENT_PAIR_NP) + { + insnp = ix86_pent_find_pair (e_ready-1, ready, + PENT_PAIR_UV, *e_ready); + if (insnp) + pair2 = PENT_PAIR_UV; } - /* Source and destination match. */ + if (pair2 == PENT_PAIR_NP) + return; + + /* Found something! Decide if we need to swap the order. */ + if (pair1 == PENT_PAIR_PV || pair2 == PENT_PAIR_PU + || (pair1 == PENT_PAIR_UV && pair2 == PENT_PAIR_UV + && ix86_safe_memory (*e_ready) == MEMORY_BOTH + && ix86_safe_memory (*insnp) == MEMORY_LOAD)) + ix86_reorder_insn (insnp, e_ready); + else + ix86_reorder_insn (insnp, e_ready - 1); +} + +static void +ix86_sched_reorder_ppro (ready, e_ready) + rtx *ready; + rtx *e_ready; +{ + rtx decode[3]; + enum attr_ppro_uops cur_uops; + int issued_this_cycle; + rtx *insnp; + int i; + + /* At this point .ppro.decode contains the state of the three + decoders from last "cycle". That is, those insns that were + actually independent. But here we're scheduling for the + decoder, and we may find things that are decodable in the + same cycle. */ + + memcpy (decode, ix86_sched_data.ppro.decode, sizeof (decode)); + issued_this_cycle = 0; - /* Handle variable shift. */ - if (REG_P (operands[2])) - switch (GET_MODE (operands[0])) + insnp = e_ready; + cur_uops = ix86_safe_ppro_uops (*insnp); + + /* If the decoders are empty, and we've a complex insn at the + head of the priority queue, let it issue without complaint. */ + if (decode[0] == NULL) + { + if (cur_uops == PPRO_UOPS_MANY) + { + decode[0] = *insnp; + goto ppro_done; + } + + /* Otherwise, search for a 2-4 uop unsn to issue. */ + while (cur_uops != PPRO_UOPS_FEW) + { + if (insnp == ready) + break; + cur_uops = ix86_safe_ppro_uops (*--insnp); + } + + /* If so, move it to the head of the line. */ + if (cur_uops == PPRO_UOPS_FEW) + ix86_reorder_insn (insnp, e_ready); + + /* Issue the head of the queue. */ + issued_this_cycle = 1; + decode[0] = *e_ready--; + } + + /* Look for simple insns to fill in the other two slots. */ + for (i = 1; i < 3; ++i) + if (decode[i] == NULL) { - case SImode: - return AS2 (sal%L0,%b2,%0); - case HImode: - if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + if (ready >= e_ready) + goto ppro_done; + + insnp = e_ready; + cur_uops = ix86_safe_ppro_uops (*insnp); + while (cur_uops != PPRO_UOPS_ONE) { - CC_STATUS_INIT; - return AS2 (sal%L0,%b2,%k0); + if (insnp == ready) + break; + cur_uops = ix86_safe_ppro_uops (*--insnp); } - else - return AS2 (sal%W0,%b2,%0); - case QImode: - return AS2 (sal%B0,%b2,%0); - default: - abort (); + + /* Found one. Move it to the head of the queue and issue it. */ + if (cur_uops == PPRO_UOPS_ONE) + { + ix86_reorder_insn (insnp, e_ready); + decode[i] = *e_ready--; + issued_this_cycle++; + continue; + } + + /* ??? Didn't find one. Ideally, here we would do a lazy split + of 2-uop insns, issue one and queue the other. */ } - /* Always perform shift by 1 using an add instruction. */ - if (REG_P (operands[0]) && operands[2] == const1_rtx) - switch (GET_MODE (operands[0])) + ppro_done: + if (issued_this_cycle == 0) + issued_this_cycle = 1; + ix86_sched_data.ppro.issued_this_cycle = issued_this_cycle; +} + +/* We are about to being issuing insns for this clock cycle. + Override the default sort algorithm to better slot instructions. */ +static int +ix86_sched_reorder (dump, sched_verbose, ready, n_readyp, clock_var) + FILE *dump ATTRIBUTE_UNUSED; + int sched_verbose ATTRIBUTE_UNUSED; + rtx *ready; + int *n_readyp; + int clock_var ATTRIBUTE_UNUSED; +{ + int n_ready = *n_readyp; + rtx *e_ready = ready + n_ready - 1; + + if (n_ready < 2) + goto out; + + switch (ix86_cpu) + { + default: + break; + + case PROCESSOR_PENTIUM: + ix86_sched_reorder_pentium (ready, e_ready); + break; + + case PROCESSOR_PENTIUMPRO: + ix86_sched_reorder_ppro (ready, e_ready); + break; + } + +out: + return ix86_issue_rate (); +} + +/* We are about to issue INSN. Return the number of insns left on the + ready queue that can be issued this cycle. */ + +static int +ix86_variable_issue (dump, sched_verbose, insn, can_issue_more) + FILE *dump; + int sched_verbose; + rtx insn; + int can_issue_more; +{ + int i; + switch (ix86_cpu) + { + default: + return can_issue_more - 1; + + case PROCESSOR_PENTIUMPRO: { - case SImode: - return AS2 (add%L0,%0,%0); - case HImode: - if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + enum attr_ppro_uops uops = ix86_safe_ppro_uops (insn); + + if (uops == PPRO_UOPS_MANY) { - CC_STATUS_INIT; - return AS2 (add%L0,%k0,%k0); + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = insn; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = NULL; + } + else if (uops == PPRO_UOPS_FEW) + { + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = insn; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; } else - return AS2 (add%W0,%0,%0); - case QImode: - return AS2 (add%B0,%0,%0); - default: - abort (); + { + for (i = 0; i < 3; ++i) + if (ix86_sched_data.ppro.decode[i] == NULL) + { + ix86_sched_data.ppro.decode[i] = insn; + break; + } + if (i == 3) + abort (); + if (i == 2) + { + if (sched_verbose) + ix86_dump_ppro_packet (dump); + ix86_sched_data.ppro.decode[0] = NULL; + ix86_sched_data.ppro.decode[1] = NULL; + ix86_sched_data.ppro.decode[2] = NULL; + } + } } + return --ix86_sched_data.ppro.issued_this_cycle; + } +} + +/* Walk through INSNS and look for MEM references whose address is DSTREG or + SRCREG and set the memory attribute to those of DSTREF and SRCREF, as + appropriate. */ -#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) +void +ix86_set_move_mem_attrs (insns, dstref, srcref, dstreg, srcreg) + rtx insns; + rtx dstref, srcref, dstreg, srcreg; +{ + rtx insn; + + for (insn = insns; insn != 0 ; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + ix86_set_move_mem_attrs_1 (PATTERN (insn), dstref, srcref, + dstreg, srcreg); +} + +/* Subroutine of above to actually do the updating by recursively walking + the rtx. */ + +static void +ix86_set_move_mem_attrs_1 (x, dstref, srcref, dstreg, srcreg) + rtx x; + rtx dstref, srcref, dstreg, srcreg; +{ + enum rtx_code code = GET_CODE (x); + const char *format_ptr = GET_RTX_FORMAT (code); + int i, j; + + if (code == MEM && XEXP (x, 0) == dstreg) + MEM_COPY_ATTRIBUTES (x, dstref); + else if (code == MEM && XEXP (x, 0) == srcreg) + MEM_COPY_ATTRIBUTES (x, srcref); + + for (i = 0; i < GET_RTX_LENGTH (code); i++, format_ptr++) { - 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); + if (*format_ptr == 'e') + ix86_set_move_mem_attrs_1 (XEXP (x, i), dstref, srcref, + dstreg, srcreg); + else if (*format_ptr == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + ix86_set_move_mem_attrs_1 (XVECEXP (x, i, j), dstref, srcref, + dstreg, srcreg); } -#endif +} + +/* Compute the alignment given to a constant that is being placed in memory. + EXP is the constant and ALIGN is the alignment that the object would + ordinarily have. + The value of this function is used instead of that alignment to align + the object. */ - /* Otherwise use a shift instruction. */ - switch (GET_MODE (operands[0])) +int +ix86_constant_alignment (exp, align) + tree exp; + int align; +{ + if (TREE_CODE (exp) == REAL_CST) { - case SImode: - return AS2 (sal%L0,%2,%0); - case HImode: - if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn)) + if (TYPE_MODE (TREE_TYPE (exp)) == DFmode && align < 64) + return 64; + else if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (exp))) && align < 128) + return 128; + } + else if (TREE_CODE (exp) == STRING_CST && TREE_STRING_LENGTH (exp) >= 31 + && align < 256) + return 256; + + return align; +} + +/* 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 function is used + instead of that alignment to align the object. */ + +int +ix86_data_alignment (type, align) + tree type; + int align; +{ + if (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) + return 256; + + /* x86-64 ABI requires arrays greater than 16 bytes to be aligned + to 16byte boundary. */ + if (TARGET_64BIT) + { + if (AGGREGATE_TYPE_P (type) + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 128 + || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 128) + return 128; + } + + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (TYPE_MODE (TREE_TYPE (type)) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (type))) && align < 128) + return 128; + } + else if (TREE_CODE (type) == COMPLEX_TYPE) + { + + if (TYPE_MODE (type) == DCmode && align < 64) + return 64; + if (TYPE_MODE (type) == XCmode && align < 128) + return 128; + } + else if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && TYPE_FIELDS (type)) + { + if (DECL_MODE (TYPE_FIELDS (type)) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (DECL_MODE (TYPE_FIELDS (type))) && align < 128) + return 128; + } + else if (TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == VECTOR_TYPE + || TREE_CODE (type) == INTEGER_TYPE) + { + if (TYPE_MODE (type) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (TYPE_MODE (type)) && align < 128) + return 128; + } + + return align; +} + +/* 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. */ + +int +ix86_local_alignment (type, align) + tree type; + int align; +{ + /* x86-64 ABI requires arrays greater than 16 bytes to be aligned + to 16byte boundary. */ + if (TARGET_64BIT) + { + if (AGGREGATE_TYPE_P (type) + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 + || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 128) + return 128; + } + if (TREE_CODE (type) == ARRAY_TYPE) + { + if (TYPE_MODE (TREE_TYPE (type)) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (type))) && align < 128) + return 128; + } + else if (TREE_CODE (type) == COMPLEX_TYPE) + { + if (TYPE_MODE (type) == DCmode && align < 64) + return 64; + if (TYPE_MODE (type) == XCmode && align < 128) + return 128; + } + else if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && TYPE_FIELDS (type)) + { + if (DECL_MODE (TYPE_FIELDS (type)) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (DECL_MODE (TYPE_FIELDS (type))) && align < 128) + return 128; + } + else if (TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == VECTOR_TYPE + || TREE_CODE (type) == INTEGER_TYPE) + { + + if (TYPE_MODE (type) == DFmode && align < 64) + return 64; + if (ALIGN_MODE_128 (TYPE_MODE (type)) && align < 128) + return 128; + } + return align; +} + +/* 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. */ +void +x86_initialize_trampoline (tramp, fnaddr, cxt) + rtx tramp, fnaddr, cxt; +{ + if (!TARGET_64BIT) + { + /* 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 (trunc_int_for_mode (0xb9, QImode))); + 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 (trunc_int_for_mode (0xe9, QImode))); + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 6)), disp); + } + else + { + int offset = 0; + /* Try to load address using shorter movl instead of movabs. + We may want to support movq for kernel mode, but kernel does not use + trampolines at the moment. */ + if (x86_64_zero_extended_value (fnaddr)) { - CC_STATUS_INIT; - return AS2 (sal%L0,%2,%k0); + fnaddr = copy_to_mode_reg (DImode, fnaddr); + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)), + GEN_INT (trunc_int_for_mode (0xbb41, HImode))); + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, offset + 2)), + gen_lowpart (SImode, fnaddr)); + offset += 6; } else - return AS2 (sal%W0,%2,%0); - case QImode: - return AS2 (sal%B0,%2,%0); - default: - abort (); + { + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)), + GEN_INT (trunc_int_for_mode (0xbb49, HImode))); + emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, offset + 2)), + fnaddr); + offset += 10; + } + /* Load static chain using movabs to r10. */ + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)), + GEN_INT (trunc_int_for_mode (0xba49, HImode))); + emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, offset + 2)), + cxt); + offset += 10; + /* Jump to the r11 */ + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)), + GEN_INT (trunc_int_for_mode (0xff49, HImode))); + emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, offset+2)), + GEN_INT (trunc_int_for_mode (0xe3, QImode))); + offset += 3; + if (offset > TRAMPOLINE_SIZE) + abort (); } } + +#define def_builtin(MASK, NAME, TYPE, CODE) \ +do { \ + if ((MASK) & target_flags) \ + builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL); \ +} while (0) -/* 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. */ +struct builtin_description +{ + const unsigned int mask; + const enum insn_code icode; + const char *const name; + const enum ix86_builtins code; + const enum rtx_code comparison; + const unsigned int flag; +}; -int -memory_address_info (addr, disp_length) - rtx addr; - int disp_length; +static const struct builtin_description bdesc_comi[] = { - rtx base, index, disp, scale; - rtx op0, op1; - int len; + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, LE, 0 }, + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, LT, 1 }, + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, LE, 1 }, + { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, NE, 0 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, LE, 0 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, LT, 1 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, LE, 1 }, + { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, NE, 0 } +}; - if (GET_CODE (addr) == PRE_DEC - || GET_CODE (addr) == POST_INC) +static const struct builtin_description bdesc_2arg[] = +{ + /* SSE */ + { MASK_SSE, CODE_FOR_addv4sf3, "__builtin_ia32_addps", IX86_BUILTIN_ADDPS, 0, 0 }, + { MASK_SSE, CODE_FOR_subv4sf3, "__builtin_ia32_subps", IX86_BUILTIN_SUBPS, 0, 0 }, + { MASK_SSE, CODE_FOR_mulv4sf3, "__builtin_ia32_mulps", IX86_BUILTIN_MULPS, 0, 0 }, + { MASK_SSE, CODE_FOR_divv4sf3, "__builtin_ia32_divps", IX86_BUILTIN_DIVPS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmaddv4sf3, "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsubv4sf3, "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmmulv4sf3, "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmdivv4sf3, "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 }, + + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT, 1 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE, 1 }, + { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, EQ, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, LT, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, LE, 0 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, LT, 1 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, LE, 1 }, + { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgtss", IX86_BUILTIN_CMPGTSS, LT, 1 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgess", IX86_BUILTIN_CMPGESS, LE, 1 }, + { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, EQ, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, LT, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, LE, 0 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngtss", IX86_BUILTIN_CMPNGTSS, LT, 1 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, LE, 1 }, + { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, UNORDERED, 0 }, + + { MASK_SSE, CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 }, + { MASK_SSE, CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 }, + { MASK_SSE, CODE_FOR_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 }, + + { MASK_SSE, CODE_FOR_sse_movss, "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_movhlps, "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_movlhps, "__builtin_ia32_movlhps", IX86_BUILTIN_MOVLHPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_unpckhps, "__builtin_ia32_unpckhps", IX86_BUILTIN_UNPCKHPS, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_unpcklps, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, 0, 0 }, + + /* MMX */ + { MASK_MMX, CODE_FOR_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 }, + { MASK_MMX, CODE_FOR_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 }, + { MASK_MMX, CODE_FOR_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 }, + { MASK_MMX, CODE_FOR_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 }, + { MASK_MMX, CODE_FOR_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 }, + { MASK_MMX, CODE_FOR_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 }, + + { MASK_MMX, CODE_FOR_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 }, + { MASK_MMX, CODE_FOR_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 }, + { MASK_MMX, CODE_FOR_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 }, + { MASK_MMX, CODE_FOR_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 }, + { MASK_MMX, CODE_FOR_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 }, + + { MASK_MMX, CODE_FOR_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 }, + { MASK_MMX, CODE_FOR_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 }, + + { MASK_MMX, CODE_FOR_mmx_anddi3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_nanddi3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_iordi3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_xordi3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 }, + + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, 0, 0 }, + + { MASK_MMX, CODE_FOR_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 }, + { MASK_MMX, CODE_FOR_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 }, + { MASK_MMX, CODE_FOR_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 }, + { MASK_MMX, CODE_FOR_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 }, + + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 }, + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 }, + + { MASK_MMX, CODE_FOR_mmx_punpckhbw, "__builtin_ia32_punpckhbw", IX86_BUILTIN_PUNPCKHBW, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_punpckhwd, "__builtin_ia32_punpckhwd", IX86_BUILTIN_PUNPCKHWD, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_punpckhdq, "__builtin_ia32_punpckhdq", IX86_BUILTIN_PUNPCKHDQ, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_punpcklbw, "__builtin_ia32_punpcklbw", IX86_BUILTIN_PUNPCKLBW, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_punpcklwd, "__builtin_ia32_punpcklwd", IX86_BUILTIN_PUNPCKLWD, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_punpckldq, "__builtin_ia32_punpckldq", IX86_BUILTIN_PUNPCKLDQ, 0, 0 }, + + /* Special. */ + { MASK_MMX, CODE_FOR_mmx_packsswb, 0, IX86_BUILTIN_PACKSSWB, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_packssdw, 0, IX86_BUILTIN_PACKSSDW, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_packuswb, 0, IX86_BUILTIN_PACKUSWB, 0, 0 }, + + { MASK_SSE, CODE_FOR_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 }, + + { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 }, + { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQ, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQI, 0, 0 }, + + { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 }, + { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQ, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQI, 0, 0 }, + + { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 }, + { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 }, + + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_psadbw, 0, IX86_BUILTIN_PSADBW, 0, 0 }, + { MASK_MMX, CODE_FOR_mmx_pmaddwd, 0, IX86_BUILTIN_PMADDWD, 0, 0 } + +}; + +static const struct builtin_description bdesc_1arg[] = +{ + { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB, 0, 0 }, + { MASK_SSE, CODE_FOR_sse_movmskps, 0, IX86_BUILTIN_MOVMSKPS, 0, 0 }, + + { MASK_SSE, CODE_FOR_sqrtv4sf2, 0, IX86_BUILTIN_SQRTPS, 0, 0 }, + { MASK_SSE, CODE_FOR_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 }, + { MASK_SSE, CODE_FOR_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 }, + + { MASK_SSE, CODE_FOR_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 }, + { MASK_SSE, CODE_FOR_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 }, + { MASK_SSE, CODE_FOR_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 }, + { MASK_SSE, CODE_FOR_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 } + +}; + +void +ix86_init_builtins () +{ + if (TARGET_MMX) + ix86_init_mmx_sse_builtins (); +} + +/* Set up all the MMX/SSE builtins. This is not called if TARGET_MMX + is zero. Otherwise, if TARGET_SSE is not set, only expand the MMX + builtins. */ +static void +ix86_init_mmx_sse_builtins () +{ + const struct builtin_description * d; + size_t i; + tree endlink = void_list_node; + + tree pchar_type_node = build_pointer_type (char_type_node); + tree pfloat_type_node = build_pointer_type (float_type_node); + tree pv2si_type_node = build_pointer_type (V2SI_type_node); + tree pdi_type_node = build_pointer_type (long_long_unsigned_type_node); + + /* Comparisons. */ + tree int_ftype_v4sf_v4sf + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, + V4SF_type_node, + endlink))); + tree v4si_ftype_v4sf_v4sf + = build_function_type (V4SI_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, + V4SF_type_node, + endlink))); + /* MMX/SSE/integer conversions. */ + tree int_ftype_v4sf + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink)); + tree int_ftype_v8qi + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + endlink)); + tree v4sf_ftype_v4sf_int + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + tree v4sf_ftype_v4sf_v2si + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + endlink))); + tree int_ftype_v4hi_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + tree v4hi_ftype_v4hi_int_int + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + /* Miscellaneous. */ + tree v8qi_ftype_v4hi_v4hi + = build_function_type (V8QI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + endlink))); + tree v4hi_ftype_v2si_v2si + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + endlink))); + tree v4sf_ftype_v4sf_v4sf_int + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, + integer_type_node, + endlink)))); + tree v4hi_ftype_v8qi_v8qi + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + endlink))); + tree v2si_ftype_v4hi_v4hi + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + endlink))); + tree v4hi_ftype_v4hi_int + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + tree v4hi_ftype_v4hi_di + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, + long_long_integer_type_node, + endlink))); + tree v2si_ftype_v2si_di + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + tree_cons (NULL_TREE, + long_long_integer_type_node, + endlink))); + tree void_ftype_void + = build_function_type (void_type_node, endlink); + tree void_ftype_unsigned + = build_function_type (void_type_node, + tree_cons (NULL_TREE, unsigned_type_node, + endlink)); + tree unsigned_ftype_void + = build_function_type (unsigned_type_node, endlink); + tree di_ftype_void + = build_function_type (long_long_unsigned_type_node, endlink); + tree v4sf_ftype_void + = build_function_type (V4SF_type_node, endlink); + tree v2si_ftype_v4sf + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink)); + /* Loads/stores. */ + tree maskmovq_args = tree_cons (NULL_TREE, V8QI_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + tree_cons (NULL_TREE, + pchar_type_node, + endlink))); + tree void_ftype_v8qi_v8qi_pchar + = build_function_type (void_type_node, maskmovq_args); + tree v4sf_ftype_pfloat + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, pfloat_type_node, + endlink)); + /* @@@ the type is bogus */ + tree v4sf_ftype_v4sf_pv2si + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, pv2si_type_node, + endlink))); + tree void_ftype_pv2si_v4sf + = build_function_type (void_type_node, + tree_cons (NULL_TREE, pv2si_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink))); + tree void_ftype_pfloat_v4sf + = build_function_type (void_type_node, + tree_cons (NULL_TREE, pfloat_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink))); + tree void_ftype_pdi_di + = build_function_type (void_type_node, + tree_cons (NULL_TREE, pdi_type_node, + tree_cons (NULL_TREE, + long_long_unsigned_type_node, + endlink))); + /* Normal vector unops. */ + tree v4sf_ftype_v4sf + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink)); + + /* Normal vector binops. */ + tree v4sf_ftype_v4sf_v4sf + = build_function_type (V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + tree_cons (NULL_TREE, V4SF_type_node, + endlink))); + tree v8qi_ftype_v8qi_v8qi + = build_function_type (V8QI_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + tree_cons (NULL_TREE, V8QI_type_node, + endlink))); + tree v4hi_ftype_v4hi_v4hi + = build_function_type (V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + tree_cons (NULL_TREE, V4HI_type_node, + endlink))); + tree v2si_ftype_v2si_v2si + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + endlink))); + tree di_ftype_di_di + = build_function_type (long_long_unsigned_type_node, + tree_cons (NULL_TREE, long_long_unsigned_type_node, + tree_cons (NULL_TREE, + long_long_unsigned_type_node, + endlink))); + + tree v2si_ftype_v2sf + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V2SF_type_node, + endlink)); + tree v2sf_ftype_v2si + = build_function_type (V2SF_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + endlink)); + tree v2si_ftype_v2si + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V2SI_type_node, + endlink)); + tree v2sf_ftype_v2sf + = build_function_type (V2SF_type_node, + tree_cons (NULL_TREE, V2SF_type_node, + endlink)); + tree v2sf_ftype_v2sf_v2sf + = build_function_type (V2SF_type_node, + tree_cons (NULL_TREE, V2SF_type_node, + tree_cons (NULL_TREE, + V2SF_type_node, + endlink))); + tree v2si_ftype_v2sf_v2sf + = build_function_type (V2SI_type_node, + tree_cons (NULL_TREE, V2SF_type_node, + tree_cons (NULL_TREE, + V2SF_type_node, + endlink))); + + /* Add all builtins that are more or less simple operations on two + operands. */ + for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++) + { + /* Use one of the operands; the target can have a different mode for + mask-generating compares. */ + enum machine_mode mode; + tree type; + + if (d->name == 0) + continue; + mode = insn_data[d->icode].operand[1].mode; + + switch (mode) + { + case V4SFmode: + type = v4sf_ftype_v4sf_v4sf; + break; + case V8QImode: + type = v8qi_ftype_v8qi_v8qi; + break; + case V4HImode: + type = v4hi_ftype_v4hi_v4hi; + break; + case V2SImode: + type = v2si_ftype_v2si_v2si; + break; + case DImode: + type = di_ftype_di_di; + break; + + default: + abort (); + } + + /* Override for comparisons. */ + if (d->icode == CODE_FOR_maskcmpv4sf3 + || d->icode == CODE_FOR_maskncmpv4sf3 + || d->icode == CODE_FOR_vmmaskcmpv4sf3 + || d->icode == CODE_FOR_vmmaskncmpv4sf3) + type = v4si_ftype_v4sf_v4sf; + + def_builtin (d->mask, d->name, type, d->code); + } + + /* Add the remaining MMX insns with somewhat more complicated types. */ + def_builtin (MASK_MMX, "__builtin_ia32_mmx_zero", di_ftype_void, IX86_BUILTIN_MMX_ZERO); + def_builtin (MASK_MMX, "__builtin_ia32_emms", void_ftype_void, IX86_BUILTIN_EMMS); + def_builtin (MASK_MMX, "__builtin_ia32_ldmxcsr", void_ftype_unsigned, IX86_BUILTIN_LDMXCSR); + def_builtin (MASK_MMX, "__builtin_ia32_stmxcsr", unsigned_ftype_void, IX86_BUILTIN_STMXCSR); + def_builtin (MASK_MMX, "__builtin_ia32_psllw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSLLW); + def_builtin (MASK_MMX, "__builtin_ia32_pslld", v2si_ftype_v2si_di, IX86_BUILTIN_PSLLD); + def_builtin (MASK_MMX, "__builtin_ia32_psllq", di_ftype_di_di, IX86_BUILTIN_PSLLQ); + + def_builtin (MASK_MMX, "__builtin_ia32_psrlw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRLW); + def_builtin (MASK_MMX, "__builtin_ia32_psrld", v2si_ftype_v2si_di, IX86_BUILTIN_PSRLD); + def_builtin (MASK_MMX, "__builtin_ia32_psrlq", di_ftype_di_di, IX86_BUILTIN_PSRLQ); + + def_builtin (MASK_MMX, "__builtin_ia32_psraw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRAW); + def_builtin (MASK_MMX, "__builtin_ia32_psrad", v2si_ftype_v2si_di, IX86_BUILTIN_PSRAD); + + def_builtin (MASK_MMX, "__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW); + def_builtin (MASK_MMX, "__builtin_ia32_pmaddwd", v2si_ftype_v4hi_v4hi, IX86_BUILTIN_PMADDWD); + + /* comi/ucomi insns. */ + for (i = 0, d = bdesc_comi; i < sizeof (bdesc_comi) / sizeof *d; i++, d++) + def_builtin (d->mask, d->name, int_ftype_v4sf_v4sf, d->code); + + def_builtin (MASK_MMX, "__builtin_ia32_packsswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKSSWB); + def_builtin (MASK_MMX, "__builtin_ia32_packssdw", v4hi_ftype_v2si_v2si, IX86_BUILTIN_PACKSSDW); + def_builtin (MASK_MMX, "__builtin_ia32_packuswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKUSWB); + + def_builtin (MASK_SSE, "__builtin_ia32_cvtpi2ps", v4sf_ftype_v4sf_v2si, IX86_BUILTIN_CVTPI2PS); + def_builtin (MASK_SSE, "__builtin_ia32_cvtps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTPS2PI); + def_builtin (MASK_SSE, "__builtin_ia32_cvtsi2ss", v4sf_ftype_v4sf_int, IX86_BUILTIN_CVTSI2SS); + def_builtin (MASK_SSE, "__builtin_ia32_cvtss2si", int_ftype_v4sf, IX86_BUILTIN_CVTSS2SI); + def_builtin (MASK_SSE, "__builtin_ia32_cvttps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTTPS2PI); + def_builtin (MASK_SSE, "__builtin_ia32_cvttss2si", int_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI); + + def_builtin (MASK_SSE, "__builtin_ia32_andps", v4sf_ftype_v4sf_v4sf, IX86_BUILTIN_ANDPS); + def_builtin (MASK_SSE, "__builtin_ia32_andnps", v4sf_ftype_v4sf_v4sf, IX86_BUILTIN_ANDNPS); + def_builtin (MASK_SSE, "__builtin_ia32_orps", v4sf_ftype_v4sf_v4sf, IX86_BUILTIN_ORPS); + def_builtin (MASK_SSE, "__builtin_ia32_xorps", v4sf_ftype_v4sf_v4sf, IX86_BUILTIN_XORPS); + + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pextrw", int_ftype_v4hi_int, IX86_BUILTIN_PEXTRW); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pinsrw", v4hi_ftype_v4hi_int_int, IX86_BUILTIN_PINSRW); + + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_maskmovq", void_ftype_v8qi_v8qi_pchar, IX86_BUILTIN_MASKMOVQ); + + def_builtin (MASK_SSE, "__builtin_ia32_loadaps", v4sf_ftype_pfloat, IX86_BUILTIN_LOADAPS); + def_builtin (MASK_SSE, "__builtin_ia32_loadups", v4sf_ftype_pfloat, IX86_BUILTIN_LOADUPS); + def_builtin (MASK_SSE, "__builtin_ia32_loadss", v4sf_ftype_pfloat, IX86_BUILTIN_LOADSS); + def_builtin (MASK_SSE, "__builtin_ia32_storeaps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREAPS); + def_builtin (MASK_SSE, "__builtin_ia32_storeups", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREUPS); + def_builtin (MASK_SSE, "__builtin_ia32_storess", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORESS); + + def_builtin (MASK_SSE, "__builtin_ia32_loadhps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADHPS); + def_builtin (MASK_SSE, "__builtin_ia32_loadlps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADLPS); + def_builtin (MASK_SSE, "__builtin_ia32_storehps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STOREHPS); + def_builtin (MASK_SSE, "__builtin_ia32_storelps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STORELPS); + + def_builtin (MASK_SSE, "__builtin_ia32_movmskps", int_ftype_v4sf, IX86_BUILTIN_MOVMSKPS); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pmovmskb", int_ftype_v8qi, IX86_BUILTIN_PMOVMSKB); + def_builtin (MASK_SSE, "__builtin_ia32_movntps", void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTPS); + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_movntq", void_ftype_pdi_di, IX86_BUILTIN_MOVNTQ); + + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_sfence", void_ftype_void, IX86_BUILTIN_SFENCE); + + def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_psadbw", v4hi_ftype_v8qi_v8qi, IX86_BUILTIN_PSADBW); + + def_builtin (MASK_SSE, "__builtin_ia32_rcpps", v4sf_ftype_v4sf, IX86_BUILTIN_RCPPS); + def_builtin (MASK_SSE, "__builtin_ia32_rcpss", v4sf_ftype_v4sf, IX86_BUILTIN_RCPSS); + def_builtin (MASK_SSE, "__builtin_ia32_rsqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTPS); + def_builtin (MASK_SSE, "__builtin_ia32_rsqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTSS); + def_builtin (MASK_SSE, "__builtin_ia32_sqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTPS); + def_builtin (MASK_SSE, "__builtin_ia32_sqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTSS); + + def_builtin (MASK_SSE, "__builtin_ia32_shufps", v4sf_ftype_v4sf_v4sf_int, IX86_BUILTIN_SHUFPS); + + /* Original 3DNow! */ + def_builtin (MASK_3DNOW, "__builtin_ia32_femms", void_ftype_void, IX86_BUILTIN_FEMMS); + def_builtin (MASK_3DNOW, "__builtin_ia32_pavgusb", v8qi_ftype_v8qi_v8qi, IX86_BUILTIN_PAVGUSB); + def_builtin (MASK_3DNOW, "__builtin_ia32_pf2id", v2si_ftype_v2sf, IX86_BUILTIN_PF2ID); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFACC); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfadd", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFADD); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpeq", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPEQ); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpge", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGE); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpgt", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGT); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfmax", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMAX); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfmin", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMIN); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfmul", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMUL); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcp", v2sf_ftype_v2sf, IX86_BUILTIN_PFRCP); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT1); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit2", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT2); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqrt", v2sf_ftype_v2sf, IX86_BUILTIN_PFRSQRT); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRSQIT1); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfsub", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUB); + def_builtin (MASK_3DNOW, "__builtin_ia32_pfsubr", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUBR); + def_builtin (MASK_3DNOW, "__builtin_ia32_pi2fd", v2sf_ftype_v2si, IX86_BUILTIN_PI2FD); + def_builtin (MASK_3DNOW, "__builtin_ia32_pmulhrw", v4hi_ftype_v4hi_v4hi, IX86_BUILTIN_PMULHRW); + + /* 3DNow! extension as used in the Athlon CPU. */ + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pf2iw", v2si_ftype_v2sf, IX86_BUILTIN_PF2IW); + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFNACC); + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfpnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFPNACC); + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pi2fw", v2sf_ftype_v2si, IX86_BUILTIN_PI2FW); + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsf", v2sf_ftype_v2sf, IX86_BUILTIN_PSWAPDSF); + def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsi", v2si_ftype_v2si, IX86_BUILTIN_PSWAPDSI); + + def_builtin (MASK_SSE, "__builtin_ia32_setzerops", v4sf_ftype_void, IX86_BUILTIN_SSE_ZERO); +} + +/* Errors in the source file can cause expand_expr to return const0_rtx + where we expect a vector. To avoid crashing, use one of the vector + clear instructions. */ +static rtx +safe_vector_operand (x, mode) + rtx x; + enum machine_mode mode; +{ + if (x != const0_rtx) + return x; + x = gen_reg_rtx (mode); + + if (VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode)) + emit_insn (gen_mmx_clrdi (mode == DImode ? x + : gen_rtx_SUBREG (DImode, x, 0))); + else + emit_insn (gen_sse_clrv4sf (mode == V4SFmode ? x + : gen_rtx_SUBREG (V4SFmode, x, 0))); + return x; +} + +/* Subroutine of ix86_expand_builtin to take care of binop insns. */ + +static rtx +ix86_expand_binop_builtin (icode, arglist, target) + enum insn_code icode; + tree arglist; + rtx target; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + enum machine_mode tmode = insn_data[icode].operand[0].mode; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; + enum machine_mode mode1 = insn_data[icode].operand[2].mode; + + if (VECTOR_MODE_P (mode0)) + op0 = safe_vector_operand (op0, mode0); + if (VECTOR_MODE_P (mode1)) + op1 = safe_vector_operand (op1, mode1); + + if (! target + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + + /* In case the insn wants input operands in modes different from + the result, abort. */ + if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1) + abort (); + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) return 0; + emit_insn (pat); + return target; +} - /* Register Indirect. */ - if (register_operand (addr, Pmode)) +/* In type_for_mode we restrict the ability to create TImode types + to hosts with 64-bit H_W_I. So we've defined the SSE logicals + to have a V4SFmode signature. Convert them in-place to TImode. */ + +static rtx +ix86_expand_timode_binop_builtin (icode, arglist, target) + enum insn_code icode; + tree arglist; + rtx target; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + + op0 = gen_lowpart (TImode, op0); + op1 = gen_lowpart (TImode, op1); + target = gen_reg_rtx (TImode); + + if (! (*insn_data[icode].operand[1].predicate) (op0, TImode)) + op0 = copy_to_mode_reg (TImode, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, TImode)) + op1 = copy_to_mode_reg (TImode, op1); + + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + + return gen_lowpart (V4SFmode, target); +} + +/* Subroutine of ix86_expand_builtin to take care of stores. */ + +static rtx +ix86_expand_store_builtin (icode, arglist) + enum insn_code icode; + tree arglist; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + enum machine_mode mode0 = insn_data[icode].operand[0].mode; + enum machine_mode mode1 = insn_data[icode].operand[1].mode; + + if (VECTOR_MODE_P (mode1)) + op1 = safe_vector_operand (op1, mode1); + + op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0)); + pat = GEN_FCN (icode) (op0, op1); + if (pat) + emit_insn (pat); + return 0; +} + +/* Subroutine of ix86_expand_builtin to take care of unop insns. */ + +static rtx +ix86_expand_unop_builtin (icode, arglist, target, do_load) + enum insn_code icode; + tree arglist; + rtx target; + int do_load; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + enum machine_mode tmode = insn_data[icode].operand[0].mode; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; + + if (! target + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + if (do_load) + op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0)); + else { - /* Special cases: ebp and esp need the two-byte modrm form. + if (VECTOR_MODE_P (mode0)) + op0 = safe_vector_operand (op0, mode0); - 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; + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); } - /* Direct Addressing. */ - if (CONSTANT_P (addr)) - return 4; + pat = GEN_FCN (icode) (target, op0); + if (! pat) + return 0; + emit_insn (pat); + return target; +} - index = base = disp = scale = NULL_RTX; - op0 = XEXP (addr, 0); - op1 = XEXP (addr, 1); +/* Subroutine of ix86_expand_builtin to take care of three special unop insns: + sqrtss, rsqrtss, rcpss. */ - if (GET_CODE (addr) == PLUS) - { - if (register_operand (op0, Pmode)) +static rtx +ix86_expand_unop1_builtin (icode, arglist, target) + enum insn_code icode; + tree arglist; + rtx target; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + enum machine_mode tmode = insn_data[icode].operand[0].mode; + enum machine_mode mode0 = insn_data[icode].operand[1].mode; + + if (! target + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + + if (VECTOR_MODE_P (mode0)) + op0 = safe_vector_operand (op0, mode0); + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + pat = GEN_FCN (icode) (target, op0, op0); + if (! pat) + return 0; + emit_insn (pat); + return target; +} + +/* Subroutine of ix86_expand_builtin to take care of comparison insns. */ + +static rtx +ix86_expand_sse_compare (d, arglist, target) + const struct builtin_description *d; + tree arglist; + rtx target; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op2; + enum machine_mode tmode = insn_data[d->icode].operand[0].mode; + enum machine_mode mode0 = insn_data[d->icode].operand[1].mode; + enum machine_mode mode1 = insn_data[d->icode].operand[2].mode; + enum rtx_code comparison = d->comparison; + + if (VECTOR_MODE_P (mode0)) + op0 = safe_vector_operand (op0, mode0); + if (VECTOR_MODE_P (mode1)) + op1 = safe_vector_operand (op1, mode1); + + /* Swap operands if we have a comparison that isn't available in + hardware. */ + if (d->flag) + { + rtx tmp = gen_reg_rtx (mode1); + emit_move_insn (tmp, op1); + op1 = op0; + op0 = tmp; + } + + if (! target + || GET_MODE (target) != tmode + || ! (*insn_data[d->icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + + if (! (*insn_data[d->icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[d->icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1); + pat = GEN_FCN (d->icode) (target, op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + return target; +} + +/* Subroutine of ix86_expand_builtin to take care of comi insns. */ + +static rtx +ix86_expand_sse_comi (d, arglist, target) + const struct builtin_description *d; + tree arglist; + rtx target; +{ + rtx pat; + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + rtx op2; + enum machine_mode mode0 = insn_data[d->icode].operand[0].mode; + enum machine_mode mode1 = insn_data[d->icode].operand[1].mode; + enum rtx_code comparison = d->comparison; + + if (VECTOR_MODE_P (mode0)) + op0 = safe_vector_operand (op0, mode0); + if (VECTOR_MODE_P (mode1)) + op1 = safe_vector_operand (op1, mode1); + + /* Swap operands if we have a comparison that isn't available in + hardware. */ + if (d->flag) + { + rtx tmp = op1; + op1 = op0; + op0 = tmp; + } + + target = gen_reg_rtx (SImode); + emit_move_insn (target, const0_rtx); + target = gen_rtx_SUBREG (QImode, target, 0); + + if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1); + pat = GEN_FCN (d->icode) (op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_STRICT_LOW_PART (VOIDmode, target), + gen_rtx_fmt_ee (comparison, QImode, + gen_rtx_REG (CCmode, FLAGS_REG), + const0_rtx))); + + return SUBREG_REG (target); +} + +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ + +rtx +ix86_expand_builtin (exp, target, subtarget, mode, ignore) + tree exp; + rtx target; + rtx subtarget ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; + int ignore ATTRIBUTE_UNUSED; +{ + const struct builtin_description *d; + size_t i; + enum insn_code icode; + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree arglist = TREE_OPERAND (exp, 1); + tree arg0, arg1, arg2; + rtx op0, op1, op2, pat; + enum machine_mode tmode, mode0, mode1, mode2; + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case IX86_BUILTIN_EMMS: + emit_insn (gen_emms ()); + return 0; + + case IX86_BUILTIN_SFENCE: + emit_insn (gen_sfence ()); + return 0; + + case IX86_BUILTIN_PEXTRW: + icode = CODE_FOR_mmx_pextrw; + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) { - if (register_operand (op1, Pmode)) - index = op0, base = op1; - else - base = op0, disp = op1; + /* @@@ better error message */ + error ("selector must be an immediate"); + return gen_reg_rtx (tmode); } - else if (GET_CODE (op0) == MULT) + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_PINSRW: + icode = CODE_FOR_mmx_pinsrw; + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + mode2 = insn_data[icode].operand[3].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) { - index = XEXP (op0, 0); - scale = XEXP (op0, 1); - if (register_operand (op1, Pmode)) - base = op1; - else - disp = op1; + /* @@@ better error message */ + error ("selector must be an immediate"); + return const0_rtx; } - else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_MASKMOVQ: + icode = CODE_FOR_mmx_maskmovq; + /* Note the arg order is different from the operand order. */ + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + arg0 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + mode0 = insn_data[icode].operand[0].mode; + mode1 = insn_data[icode].operand[1].mode; + mode2 = insn_data[icode].operand[2].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[1].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + if (! (*insn_data[icode].operand[2].predicate) (op2, mode2)) + op2 = copy_to_mode_reg (mode2, op2); + pat = GEN_FCN (icode) (op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + return 0; + + case IX86_BUILTIN_SQRTSS: + return ix86_expand_unop1_builtin (CODE_FOR_vmsqrtv4sf2, arglist, target); + case IX86_BUILTIN_RSQRTSS: + return ix86_expand_unop1_builtin (CODE_FOR_vmrsqrtv4sf2, arglist, target); + case IX86_BUILTIN_RCPSS: + return ix86_expand_unop1_builtin (CODE_FOR_vmrcpv4sf2, arglist, target); + + case IX86_BUILTIN_ANDPS: + return ix86_expand_timode_binop_builtin (CODE_FOR_sse_andti3, + arglist, target); + case IX86_BUILTIN_ANDNPS: + return ix86_expand_timode_binop_builtin (CODE_FOR_sse_nandti3, + arglist, target); + case IX86_BUILTIN_ORPS: + return ix86_expand_timode_binop_builtin (CODE_FOR_sse_iorti3, + arglist, target); + case IX86_BUILTIN_XORPS: + return ix86_expand_timode_binop_builtin (CODE_FOR_sse_xorti3, + arglist, target); + + case IX86_BUILTIN_LOADAPS: + return ix86_expand_unop_builtin (CODE_FOR_sse_movaps, arglist, target, 1); + + case IX86_BUILTIN_LOADUPS: + return ix86_expand_unop_builtin (CODE_FOR_sse_movups, arglist, target, 1); + + case IX86_BUILTIN_STOREAPS: + return ix86_expand_store_builtin (CODE_FOR_sse_movaps, arglist); + case IX86_BUILTIN_STOREUPS: + return ix86_expand_store_builtin (CODE_FOR_sse_movups, arglist); + + case IX86_BUILTIN_LOADSS: + return ix86_expand_unop_builtin (CODE_FOR_sse_loadss, arglist, target, 1); + + case IX86_BUILTIN_STORESS: + return ix86_expand_store_builtin (CODE_FOR_sse_storess, arglist); + + case IX86_BUILTIN_LOADHPS: + case IX86_BUILTIN_LOADLPS: + icode = (fcode == IX86_BUILTIN_LOADHPS + ? CODE_FOR_sse_movhps : CODE_FOR_sse_movlps); + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + op1 = gen_rtx_MEM (mode1, copy_to_mode_reg (Pmode, op1)); + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_STOREHPS: + case IX86_BUILTIN_STORELPS: + icode = (fcode == IX86_BUILTIN_STOREHPS + ? CODE_FOR_sse_movhps : CODE_FOR_sse_movlps); + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + + op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0)); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + pat = GEN_FCN (icode) (op0, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + return 0; + + case IX86_BUILTIN_MOVNTPS: + return ix86_expand_store_builtin (CODE_FOR_sse_movntv4sf, arglist); + case IX86_BUILTIN_MOVNTQ: + return ix86_expand_store_builtin (CODE_FOR_sse_movntdi, arglist); + + case IX86_BUILTIN_LDMXCSR: + op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); + target = assign_386_stack_local (SImode, 0); + emit_move_insn (target, op0); + emit_insn (gen_ldmxcsr (target)); + return 0; + + case IX86_BUILTIN_STMXCSR: + target = assign_386_stack_local (SImode, 0); + emit_insn (gen_stmxcsr (target)); + return copy_to_mode_reg (SImode, target); + + case IX86_BUILTIN_SHUFPS: + icode = CODE_FOR_sse_shufps; + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode0 = insn_data[icode].operand[1].mode; + mode1 = insn_data[icode].operand[2].mode; + mode2 = insn_data[icode].operand[3].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) { - index = XEXP (XEXP (op0, 0), 0); - scale = XEXP (XEXP (op0, 0), 1); - base = XEXP (op0, 1); - disp = op1; + /* @@@ better error message */ + error ("mask must be an immediate"); + return gen_reg_rtx (tmode); } - else if (GET_CODE (op0) == PLUS) + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1, op2); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_PSHUFW: + icode = CODE_FOR_mmx_pshufw; + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0); + op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0); + tmode = insn_data[icode].operand[0].mode; + mode1 = insn_data[icode].operand[1].mode; + mode2 = insn_data[icode].operand[2].mode; + + if (! (*insn_data[icode].operand[1].predicate) (op0, mode1)) + op0 = copy_to_mode_reg (mode1, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode2)) { - index = XEXP (op0, 0); - base = XEXP (op0, 1); - disp = op1; + /* @@@ better error message */ + error ("mask must be an immediate"); + return const0_rtx; } - else - abort (); + if (target == 0 + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + target = gen_reg_rtx (tmode); + pat = GEN_FCN (icode) (target, op0, op1); + if (! pat) + return 0; + emit_insn (pat); + return target; + + case IX86_BUILTIN_FEMMS: + emit_insn (gen_femms ()); + return NULL_RTX; + + case IX86_BUILTIN_PAVGUSB: + return ix86_expand_binop_builtin (CODE_FOR_pavgusb, arglist, target); + + case IX86_BUILTIN_PF2ID: + return ix86_expand_unop_builtin (CODE_FOR_pf2id, arglist, target, 0); + + case IX86_BUILTIN_PFACC: + return ix86_expand_binop_builtin (CODE_FOR_pfacc, arglist, target); + + case IX86_BUILTIN_PFADD: + return ix86_expand_binop_builtin (CODE_FOR_addv2sf3, arglist, target); + + case IX86_BUILTIN_PFCMPEQ: + return ix86_expand_binop_builtin (CODE_FOR_eqv2sf3, arglist, target); + + case IX86_BUILTIN_PFCMPGE: + return ix86_expand_binop_builtin (CODE_FOR_gev2sf3, arglist, target); + + case IX86_BUILTIN_PFCMPGT: + return ix86_expand_binop_builtin (CODE_FOR_gtv2sf3, arglist, target); + + case IX86_BUILTIN_PFMAX: + return ix86_expand_binop_builtin (CODE_FOR_pfmaxv2sf3, arglist, target); + + case IX86_BUILTIN_PFMIN: + return ix86_expand_binop_builtin (CODE_FOR_pfminv2sf3, arglist, target); + + case IX86_BUILTIN_PFMUL: + return ix86_expand_binop_builtin (CODE_FOR_mulv2sf3, arglist, target); + + case IX86_BUILTIN_PFRCP: + return ix86_expand_unop_builtin (CODE_FOR_pfrcpv2sf2, arglist, target, 0); + + case IX86_BUILTIN_PFRCPIT1: + return ix86_expand_binop_builtin (CODE_FOR_pfrcpit1v2sf3, arglist, target); + + case IX86_BUILTIN_PFRCPIT2: + return ix86_expand_binop_builtin (CODE_FOR_pfrcpit2v2sf3, arglist, target); + + case IX86_BUILTIN_PFRSQIT1: + return ix86_expand_binop_builtin (CODE_FOR_pfrsqit1v2sf3, arglist, target); + + case IX86_BUILTIN_PFRSQRT: + return ix86_expand_unop_builtin (CODE_FOR_pfrsqrtv2sf2, arglist, target, 0); + + case IX86_BUILTIN_PFSUB: + return ix86_expand_binop_builtin (CODE_FOR_subv2sf3, arglist, target); + + case IX86_BUILTIN_PFSUBR: + return ix86_expand_binop_builtin (CODE_FOR_subrv2sf3, arglist, target); + + case IX86_BUILTIN_PI2FD: + return ix86_expand_unop_builtin (CODE_FOR_floatv2si2, arglist, target, 0); + + case IX86_BUILTIN_PMULHRW: + return ix86_expand_binop_builtin (CODE_FOR_pmulhrwv4hi3, arglist, target); + + case IX86_BUILTIN_PF2IW: + return ix86_expand_unop_builtin (CODE_FOR_pf2iw, arglist, target, 0); + + case IX86_BUILTIN_PFNACC: + return ix86_expand_binop_builtin (CODE_FOR_pfnacc, arglist, target); + + case IX86_BUILTIN_PFPNACC: + return ix86_expand_binop_builtin (CODE_FOR_pfpnacc, arglist, target); + + case IX86_BUILTIN_PI2FW: + return ix86_expand_unop_builtin (CODE_FOR_pi2fw, arglist, target, 0); + + case IX86_BUILTIN_PSWAPDSI: + return ix86_expand_unop_builtin (CODE_FOR_pswapdv2si2, arglist, target, 0); + + case IX86_BUILTIN_PSWAPDSF: + return ix86_expand_unop_builtin (CODE_FOR_pswapdv2sf2, arglist, target, 0); + + case IX86_BUILTIN_SSE_ZERO: + target = gen_reg_rtx (V4SFmode); + emit_insn (gen_sse_clrv4sf (target)); + return target; + + case IX86_BUILTIN_MMX_ZERO: + target = gen_reg_rtx (DImode); + emit_insn (gen_mmx_clrdi (target)); + return target; + + default: + break; + } + + for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++) + if (d->code == fcode) + { + /* Compares are treated specially. */ + if (d->icode == CODE_FOR_maskcmpv4sf3 + || d->icode == CODE_FOR_vmmaskcmpv4sf3 + || d->icode == CODE_FOR_maskncmpv4sf3 + || d->icode == CODE_FOR_vmmaskncmpv4sf3) + return ix86_expand_sse_compare (d, arglist, target); + + return ix86_expand_binop_builtin (d->icode, arglist, target); + } + + for (i = 0, d = bdesc_1arg; i < sizeof (bdesc_1arg) / sizeof *d; i++, d++) + if (d->code == fcode) + return ix86_expand_unop_builtin (d->icode, arglist, target, 0); + + for (i = 0, d = bdesc_comi; i < sizeof (bdesc_comi) / sizeof *d; i++, d++) + if (d->code == fcode) + return ix86_expand_sse_comi (d, arglist, target); + + /* @@@ Should really do something sensible here. */ + return 0; +} + +/* Store OPERAND to the memory after reload is completed. This means + that we can't easily use assign_stack_local. */ +rtx +ix86_force_to_memory (mode, operand) + enum machine_mode mode; + rtx operand; +{ + rtx result; + if (!reload_completed) + abort (); + if (TARGET_64BIT && TARGET_RED_ZONE) + { + result = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + GEN_INT (-RED_ZONE_SIZE))); + emit_move_insn (result, operand); } - else if (GET_CODE (addr) == MULT - /* We're called for lea too, which implements ashift on occasion. */ - || GET_CODE (addr) == ASHIFT) + else if (TARGET_64BIT && !TARGET_RED_ZONE) { - index = XEXP (addr, 0); - scale = XEXP (addr, 1); + switch (mode) + { + case HImode: + case SImode: + operand = gen_lowpart (DImode, operand); + /* FALLTHRU */ + case DImode: + emit_insn ( + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (DImode, + gen_rtx_PRE_DEC (DImode, + stack_pointer_rtx)), + operand)); + break; + default: + abort (); + } + result = gen_rtx_MEM (mode, stack_pointer_rtx); } 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; + switch (mode) + { + case DImode: + { + rtx operands[2]; + split_di (&operand, 1, operands, operands + 1); + emit_insn ( + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, + gen_rtx_PRE_DEC (Pmode, + stack_pointer_rtx)), + operands[1])); + emit_insn ( + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, + gen_rtx_PRE_DEC (Pmode, + stack_pointer_rtx)), + operands[0])); + } + break; + case HImode: + /* It is better to store HImodes as SImodes. */ + if (!TARGET_PARTIAL_REG_STALL) + operand = gen_lowpart (SImode, operand); + /* FALLTHRU */ + case SImode: + emit_insn ( + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (GET_MODE (operand), + gen_rtx_PRE_DEC (SImode, + stack_pointer_rtx)), + operand)); + break; + default: + abort (); + } + result = gen_rtx_MEM (mode, stack_pointer_rtx); } + return result; +} - /* Special case: ebp cannot be encoded as a base without a displacement. */ - if (base == frame_pointer_rtx && !disp) - disp = const0_rtx; +/* Free operand from the memory. */ +void +ix86_free_from_memory (mode) + enum machine_mode mode; +{ + if (!TARGET_64BIT || !TARGET_RED_ZONE) + { + int size; - /* 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; + if (mode == DImode || TARGET_64BIT) + size = 8; + else if (mode == HImode && TARGET_PARTIAL_REG_STALL) + size = 2; + else + size = 4; + /* Use LEA to deallocate stack space. In peephole2 it will be converted + to pop or add instruction if registers are available. */ + emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (size)))); + } +} - /* Find the length of the displacement constant. */ - len = 0; - if (disp) +/* 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. */ +enum reg_class +ix86_preferred_reload_class (x, class) + rtx x; + enum reg_class class; +{ + if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) { - if (GET_CODE (disp) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K')) - len = 1; + /* SSE can't load any constant directly yet. */ + if (SSE_CLASS_P (class)) + return NO_REGS; + /* Floats can load 0 and 1. */ + if (MAYBE_FLOAT_CLASS_P (class) && standard_80387_constant_p (x)) + { + /* Limit class to non-SSE. Use GENERAL_REGS if possible. */ + if (MAYBE_SSE_CLASS_P (class)) + return (reg_class_subset_p (class, GENERAL_REGS) + ? GENERAL_REGS : FLOAT_REGS); + else + return class; + } + /* General regs can load everything. */ + if (reg_class_subset_p (class, GENERAL_REGS)) + return GENERAL_REGS; + /* In case we haven't resolved FLOAT or SSE yet, give up. */ + if (MAYBE_FLOAT_CLASS_P (class) || MAYBE_SSE_CLASS_P (class)) + return NO_REGS; + } + if (MAYBE_MMX_CLASS_P (class) && CONSTANT_P (x)) + return NO_REGS; + if (GET_MODE (x) == QImode && ! reg_class_subset_p (class, Q_REGS)) + return Q_REGS; + return class; +} + +/* If we are copying between general and FP registers, we need a memory + location. The same is true for SSE and MMX registers. + + The macro can't work reliably when one of the CLASSES is class containing + registers from multiple units (SSE, MMX, integer). We avoid this by never + combining those units in single alternative in the machine description. + Ensure that this constraint holds to avoid unexpected surprises. + + When STRICT is false, we are being called from REGISTER_MOVE_COST, so do not + enforce these sanity checks. */ +int +ix86_secondary_memory_needed (class1, class2, mode, strict) + enum reg_class class1, class2; + enum machine_mode mode; + int strict; +{ + if (MAYBE_FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class1) + || MAYBE_FLOAT_CLASS_P (class2) != FLOAT_CLASS_P (class2) + || MAYBE_SSE_CLASS_P (class1) != SSE_CLASS_P (class1) + || MAYBE_SSE_CLASS_P (class2) != SSE_CLASS_P (class2) + || MAYBE_MMX_CLASS_P (class1) != MMX_CLASS_P (class1) + || MAYBE_MMX_CLASS_P (class2) != MMX_CLASS_P (class2)) + { + if (strict) + abort (); else - len = 4; + return 1; } + return (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2) + || (SSE_CLASS_P (class1) != SSE_CLASS_P (class2) + && (mode) != SImode) + || (MMX_CLASS_P (class1) != MMX_CLASS_P (class2) + && (mode) != SImode)); +} +/* Return the cost of moving data from a register in class CLASS1 to + one in class CLASS2. - /* 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; + It is not required that the cost always equal 2 when FROM is the same as TO; + on some machines it is expensive to move between registers if they are not + general registers. */ +int +ix86_register_move_cost (mode, class1, class2) + enum machine_mode mode; + enum reg_class class1, class2; +{ + /* In case we require secondary memory, compute cost of the store followed + by load. In case of copying from general_purpose_register we may emit + multiple stores followed by single load causing memory size mismatch + stall. Count this as arbitarily high cost of 20. */ + if (ix86_secondary_memory_needed (class1, class2, mode, 0)) + { + int add_cost = 0; + if (CLASS_MAX_NREGS (class1, mode) > CLASS_MAX_NREGS (class2, mode)) + add_cost = 20; + return (MEMORY_MOVE_COST (mode, class1, 0) + + MEMORY_MOVE_COST (mode, class2, 1) + add_cost); + } + /* Moves between SSE/MMX and integer unit are expensive. */ + if (MMX_CLASS_P (class1) != MMX_CLASS_P (class2) + || SSE_CLASS_P (class1) != SSE_CLASS_P (class2)) + return ix86_cost->mmxsse_to_integer; + if (MAYBE_FLOAT_CLASS_P (class1)) + return ix86_cost->fp_move; + if (MAYBE_SSE_CLASS_P (class1)) + return ix86_cost->sse_move; + if (MAYBE_MMX_CLASS_P (class1)) + return ix86_cost->mmx_move; + return 2; +} - return len; +/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */ +int +ix86_hard_regno_mode_ok (regno, mode) + int regno; + enum machine_mode mode; +{ + /* Flags and only flags can only hold CCmode values. */ + if (CC_REGNO_P (regno)) + return GET_MODE_CLASS (mode) == MODE_CC; + if (GET_MODE_CLASS (mode) == MODE_CC + || GET_MODE_CLASS (mode) == MODE_RANDOM + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) + return 0; + if (FP_REGNO_P (regno)) + return VALID_FP_MODE_P (mode); + if (SSE_REGNO_P (regno)) + return VALID_SSE_REG_MODE (mode); + if (MMX_REGNO_P (regno)) + return VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode); + /* We handle both integer and floats in the general purpose registers. + In future we should be able to handle vector modes as well. */ + if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode)) + return 0; + /* Take care for QImode values - they can be in non-QI regs, but then + they do cause partial register stalls. */ + if (regno < 4 || mode != QImode || TARGET_64BIT) + return 1; + return reload_in_progress || reload_completed || !TARGET_PARTIAL_REG_STALL; +} + +/* Return 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. + + Model also increased moving costs of QImode registers in non + Q_REGS classes. + */ +int +ix86_memory_move_cost (mode, class, in) + enum machine_mode mode; + enum reg_class class; + int in; +{ + if (FLOAT_CLASS_P (class)) + { + int index; + switch (mode) + { + case SFmode: + index = 0; + break; + case DFmode: + index = 1; + break; + case XFmode: + case TFmode: + index = 2; + break; + default: + return 100; + } + return in ? ix86_cost->fp_load [index] : ix86_cost->fp_store [index]; + } + if (SSE_CLASS_P (class)) + { + int index; + switch (GET_MODE_SIZE (mode)) + { + case 4: + index = 0; + break; + case 8: + index = 1; + break; + case 16: + index = 2; + break; + default: + return 100; + } + return in ? ix86_cost->sse_load [index] : ix86_cost->sse_store [index]; + } + if (MMX_CLASS_P (class)) + { + int index; + switch (GET_MODE_SIZE (mode)) + { + case 4: + index = 0; + break; + case 8: + index = 1; + break; + default: + return 100; + } + return in ? ix86_cost->mmx_load [index] : ix86_cost->mmx_store [index]; + } + switch (GET_MODE_SIZE (mode)) + { + case 1: + if (in) + return (Q_CLASS_P (class) ? ix86_cost->int_load[0] + : ix86_cost->movzbl_load); + else + return (Q_CLASS_P (class) ? ix86_cost->int_store[0] + : ix86_cost->int_store[0] + 4); + break; + case 2: + return in ? ix86_cost->int_load[1] : ix86_cost->int_store[1]; + default: + /* Compute number of 32bit moves needed. TFmode is moved as XFmode. */ + if (mode == TFmode) + mode = XFmode; + return ((in ? ix86_cost->int_load[2] : ix86_cost->int_store[2]) + * (int) GET_MODE_SIZE (mode) / 4); + } } + +#ifdef DO_GLOBAL_CTORS_BODY +static void +ix86_svr3_asm_out_constructor (symbol, priority) + rtx symbol; + int priority ATTRIBUTE_UNUSED; +{ + init_section (); + fputs ("\tpushl $", asm_out_file); + assemble_name (asm_out_file, XSTR (symbol, 0)); + fputc ('\n', asm_out_file); +} +#endif diff --git a/contrib/gcc/config/i386/i386.h b/contrib/gcc/config/i386/i386.h index 5e27fd8..58f65c1 100644 --- a/contrib/gcc/config/i386/i386.h +++ b/contrib/gcc/config/i386/i386.h @@ -1,6 +1,6 @@ -/* 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. +/* Definitions of target machine for GNU compiler for IA-32. + Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -17,7 +17,7 @@ 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. */ +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. @@ -30,13 +30,9 @@ Boston, MA 02111-1307, USA. */ 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 + assemblers. These include RP, IP, LPREFIX, 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. */ /* Stubs for half-pic support if not OSF/1 reference platform. */ @@ -46,25 +42,56 @@ Boston, MA 02111-1307, USA. */ #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_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_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 */ + const int add; /* cost of an add instruction */ + const int lea; /* cost of a lea instruction */ + const int shift_var; /* variable shift costs */ + const int shift_const; /* constant shift costs */ + const int mult_init; /* cost of starting a multiply */ + const int mult_bit; /* cost of multiply per each bit set */ + const int divide; /* cost of a divide/mod */ + int movsx; /* The cost of movsx operation. */ + int movzx; /* The cost of movzx operation. */ + const int large_insn; /* insns larger than this cost more */ + const int move_ratio; /* The threshold of number of scalar + memory-to-memory move insns. */ + const int movzbl_load; /* cost of loading using movzbl */ + const int int_load[3]; /* cost of loading integer registers + in QImode, HImode and SImode relative + to reg-reg move (2). */ + const int int_store[3]; /* cost of storing integer register + in QImode, HImode and SImode */ + const int fp_move; /* cost of reg,reg fld/fst */ + const int fp_load[3]; /* cost of loading FP register + in SFmode, DFmode and XFmode */ + const int fp_store[3]; /* cost of storing FP register + in SFmode, DFmode and XFmode */ + const int mmx_move; /* cost of moving MMX register. */ + const int mmx_load[2]; /* cost of loading MMX register + in SImode and DImode */ + const int mmx_store[2]; /* cost of storing MMX register + in SImode and DImode */ + const int sse_move; /* cost of moving SSE register. */ + const int sse_load[3]; /* cost of loading SSE register + in SImode, DImode and TImode*/ + const int sse_store[3]; /* cost of storing SSE register + in SImode, DImode and TImode*/ + const int mmxsse_to_integer; /* cost of moving mmxsse register to + integer and vice versa. */ + const int prefetch_block; /* bytes moved to cache for prefetch. */ + const int simultaneous_prefetches; /* number of parallel prefetch + operations. */ }; -extern struct processor_costs *ix86_cost; +extern const struct processor_costs *ix86_cost; /* Run-time compilation parameters selecting different hardware subsets. */ @@ -73,29 +100,40 @@ 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 */ +#define MASK_80387 0x00000001 /* Hardware floating point */ +#define MASK_RTD 0x00000002 /* Use ret that pops args */ +#define MASK_ALIGN_DOUBLE 0x00000004 /* align doubles to 2 word boundary */ +#define MASK_SVR3_SHLIB 0x00000008 /* Uninit locals into bss */ +#define MASK_IEEE_FP 0x00000010 /* IEEE fp comparisons */ +#define MASK_FLOAT_RETURNS 0x00000020 /* Return float in st(0) */ +#define MASK_NO_FANCY_MATH_387 0x00000040 /* Disable sin, cos, sqrt */ +#define MASK_OMIT_LEAF_FRAME_POINTER 0x080 /* omit leaf frame pointers */ +#define MASK_STACK_PROBE 0x00000100 /* Enable stack probing */ +#define MASK_NO_ALIGN_STROPS 0x00000200 /* Enable aligning of string ops. */ +#define MASK_INLINE_ALL_STROPS 0x00000400 /* Inline stringops in all cases */ +#define MASK_NO_PUSH_ARGS 0x00000800 /* Use push instructions */ +#define MASK_ACCUMULATE_OUTGOING_ARGS 0x00001000/* Accumulate outgoing args */ +#define MASK_ACCUMULATE_OUTGOING_ARGS_SET 0x00002000 +#define MASK_MMX 0x00004000 /* Support MMX regs/builtins */ +#define MASK_MMX_SET 0x00008000 +#define MASK_SSE 0x00010000 /* Support SSE regs/builtins */ +#define MASK_SSE_SET 0x00020000 +#define MASK_SSE2 0x00040000 /* Support SSE2 regs/builtins */ +#define MASK_SSE2_SET 0x00080000 +#define MASK_3DNOW 0x00100000 /* Support 3Dnow builtins */ +#define MASK_3DNOW_SET 0x00200000 +#define MASK_3DNOW_A 0x00400000 /* Support Athlon 3Dnow builtins */ +#define MASK_3DNOW_A_SET 0x00800000 +#define MASK_128BIT_LONG_DOUBLE 0x01000000 /* long double size is 128bit */ +#define MASK_64BIT 0x02000000 /* Produce 64bit code */ +/* ... overlap with subtarget options starts by 0x04000000. */ +#define MASK_NO_RED_ZONE 0x04000000 /* Do not use red zone */ /* Use the floating point instructions */ #define TARGET_80387 (target_flags & MASK_80387) @@ -110,6 +148,13 @@ extern int target_flags; faster code on the pentium. */ #define TARGET_ALIGN_DOUBLE (target_flags & MASK_ALIGN_DOUBLE) +/* Use push instructions to save outgoing args. */ +#define TARGET_PUSH_ARGS (!(target_flags & MASK_NO_PUSH_ARGS)) + +/* Accumulate stack adjustments to prologue/epilogue. */ +#define TARGET_ACCUMULATE_OUTGOING_ARGS \ + (target_flags & MASK_ACCUMULATE_OUTGOING_ARGS) + /* Put uninitialized locals into bss, not data. Meaningful only on svr3. */ #define TARGET_SVR3_SHLIB (target_flags & MASK_SVR3_SHLIB) @@ -121,133 +166,248 @@ extern int target_flags; /* 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. */ + the 387 to be used, which is compatible with most calling conventions. */ #define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS) +/* Long double is 128bit instead of 96bit, even when only 80bits are used. + This mode wastes cache, but avoid misaligned data accesses and simplifies + address calculations. */ +#define TARGET_128BIT_LONG_DOUBLE (target_flags & MASK_128BIT_LONG_DOUBLE) + /* 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) +#define TARGET_OMIT_LEAF_FRAME_POINTER \ + (target_flags & MASK_OMIT_LEAF_FRAME_POINTER) /* Debug GO_IF_LEGITIMATE_ADDRESS */ -#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR) +#define TARGET_DEBUG_ADDR (ix86_debug_addr_string != 0) /* Debug FUNCTION_ARG macros */ -#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG) +#define TARGET_DEBUG_ARG (ix86_debug_arg_string != 0) -/* 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 */ +/* 64bit Sledgehammer mode */ +#ifdef TARGET_BI_ARCH +#define TARGET_64BIT (target_flags & MASK_64BIT) +#else +#ifdef TARGET_64BIT_DEFAULT +#define TARGET_64BIT 1 +#else +#define TARGET_64BIT 0 +#endif +#endif #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 TARGET_ATHLON (ix86_cpu == PROCESSOR_ATHLON) +#define TARGET_PENTIUM4 (ix86_cpu == PROCESSOR_PENTIUM4) #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; +extern const int x86_branch_hints, x86_unroll_strlen; +extern const int x86_double_with_add, x86_partial_reg_stall, x86_movx; +extern const int x86_use_loop, x86_use_fiop, x86_use_mov0; +extern const int x86_use_cltd, x86_read_modify_write; +extern const int x86_read_modify, x86_split_long_moves; +extern const int x86_promote_QImode, x86_single_stringop; +extern const int x86_himode_math, x86_qimode_math, x86_promote_qi_regs; +extern const int x86_promote_hi_regs, x86_integer_DFmode_moves; +extern const int x86_add_esp_4, x86_add_esp_8, x86_sub_esp_4, x86_sub_esp_8; +extern const int x86_partial_reg_dependency, x86_memory_mismatch_stall; +extern const int x86_accumulate_outgoing_args, x86_prologue_using_move; +extern const int x86_epilogue_using_move, x86_decompose_lea; +extern int x86_prefetch_sse; #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)) +/* For sane SSE instruction set generation we need fcomi instruction. It is + safe to enable all CMOVE instructions. */ +#define TARGET_CMOVE ((x86_cmove & (1 << ix86_arch)) || TARGET_SSE) #define TARGET_DEEP_BRANCH_PREDICTION (x86_deep_branch & CPUMASK) +#define TARGET_BRANCH_PREDICTION_HINTS (x86_branch_hints & CPUMASK) #define TARGET_DOUBLE_WITH_ADD (x86_double_with_add & CPUMASK) +#define TARGET_USE_SAHF ((x86_use_sahf & CPUMASK) && !TARGET_64BIT) +#define TARGET_MOVX (x86_movx & CPUMASK) +#define TARGET_PARTIAL_REG_STALL (x86_partial_reg_stall & CPUMASK) +#define TARGET_USE_LOOP (x86_use_loop & CPUMASK) +#define TARGET_USE_FIOP (x86_use_fiop & CPUMASK) +#define TARGET_USE_MOV0 (x86_use_mov0 & CPUMASK) +#define TARGET_USE_CLTD (x86_use_cltd & CPUMASK) +#define TARGET_SPLIT_LONG_MOVES (x86_split_long_moves & CPUMASK) +#define TARGET_READ_MODIFY_WRITE (x86_read_modify_write & CPUMASK) +#define TARGET_READ_MODIFY (x86_read_modify & CPUMASK) +#define TARGET_PROMOTE_QImode (x86_promote_QImode & CPUMASK) +#define TARGET_SINGLE_STRINGOP (x86_single_stringop & CPUMASK) +#define TARGET_QIMODE_MATH (x86_qimode_math & CPUMASK) +#define TARGET_HIMODE_MATH (x86_himode_math & CPUMASK) +#define TARGET_PROMOTE_QI_REGS (x86_promote_qi_regs & CPUMASK) +#define TARGET_PROMOTE_HI_REGS (x86_promote_hi_regs & CPUMASK) +#define TARGET_ADD_ESP_4 (x86_add_esp_4 & CPUMASK) +#define TARGET_ADD_ESP_8 (x86_add_esp_8 & CPUMASK) +#define TARGET_SUB_ESP_4 (x86_sub_esp_4 & CPUMASK) +#define TARGET_SUB_ESP_8 (x86_sub_esp_8 & CPUMASK) +#define TARGET_INTEGER_DFMODE_MOVES (x86_integer_DFmode_moves & CPUMASK) +#define TARGET_PARTIAL_REG_DEPENDENCY (x86_partial_reg_dependency & CPUMASK) +#define TARGET_MEMORY_MISMATCH_STALL (x86_memory_mismatch_stall & CPUMASK) +#define TARGET_PROLOGUE_USING_MOVE (x86_prologue_using_move & CPUMASK) +#define TARGET_EPILOGUE_USING_MOVE (x86_epilogue_using_move & CPUMASK) +#define TARGET_DECOMPOSE_LEA (x86_decompose_lea & CPUMASK) +#define TARGET_PREFETCH_SSE (x86_prefetch_sse) #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 }} +#define TARGET_ALIGN_STRINGOPS (!(target_flags & MASK_NO_ALIGN_STROPS)) +#define TARGET_INLINE_ALL_STRINGOPS (target_flags & MASK_INLINE_ALL_STROPS) + +#define ASSEMBLER_DIALECT (ix86_asm_dialect) + +#define TARGET_SSE ((target_flags & (MASK_SSE | MASK_SSE2)) != 0) +#define TARGET_SSE2 ((target_flags & MASK_SSE2) != 0) +#define TARGET_SSE_MATH ((ix86_fpmath & FPMATH_SSE) != 0) +#define TARGET_MIX_SSE_I387 ((ix86_fpmath & FPMATH_SSE) \ + && (ix86_fpmath & FPMATH_387)) +#define TARGET_MMX ((target_flags & MASK_MMX) != 0) +#define TARGET_3DNOW ((target_flags & MASK_3DNOW) != 0) +#define TARGET_3DNOW_A ((target_flags & MASK_3DNOW_A) != 0) + +#define TARGET_RED_ZONE (!(target_flags & MASK_NO_RED_ZONE)) + +#define TARGET_SWITCHES \ +{ { "80387", MASK_80387, N_("Use hardware fp") }, \ + { "no-80387", -MASK_80387, N_("Do not use hardware fp") }, \ + { "hard-float", MASK_80387, N_("Use hardware fp") }, \ + { "soft-float", -MASK_80387, N_("Do not use hardware fp") }, \ + { "no-soft-float", MASK_80387, N_("Use hardware fp") }, \ + { "386", 0, N_("") /*Deprecated.*/}, \ + { "486", 0, N_("") /*Deprecated.*/}, \ + { "pentium", 0, N_("") /*Deprecated.*/}, \ + { "pentiumpro", 0, N_("") /*Deprecated.*/}, \ + { "intel-syntax", 0, N_("") /*Deprecated.*/}, \ + { "no-intel-syntax", 0, N_("") /*Deprecated.*/}, \ + { "rtd", MASK_RTD, \ + N_("Alternate calling convention") }, \ + { "no-rtd", -MASK_RTD, \ + N_("Use normal calling convention") }, \ + { "align-double", MASK_ALIGN_DOUBLE, \ + N_("Align some doubles on dword boundary") }, \ + { "no-align-double", -MASK_ALIGN_DOUBLE, \ + N_("Align doubles on word boundary") }, \ + { "svr3-shlib", MASK_SVR3_SHLIB, \ + N_("Uninitialized locals in .bss") }, \ + { "no-svr3-shlib", -MASK_SVR3_SHLIB, \ + N_("Uninitialized locals in .data") }, \ + { "ieee-fp", MASK_IEEE_FP, \ + N_("Use IEEE math for fp comparisons") }, \ + { "no-ieee-fp", -MASK_IEEE_FP, \ + N_("Do not use IEEE math for fp comparisons") }, \ + { "fp-ret-in-387", MASK_FLOAT_RETURNS, \ + N_("Return values of functions in FPU registers") }, \ + { "no-fp-ret-in-387", -MASK_FLOAT_RETURNS , \ + N_("Do not return values of functions in FPU registers")}, \ + { "no-fancy-math-387", MASK_NO_FANCY_MATH_387, \ + N_("Do not generate sin, cos, sqrt for FPU") }, \ + { "fancy-math-387", -MASK_NO_FANCY_MATH_387, \ + N_("Generate sin, cos, sqrt for FPU")}, \ + { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER, \ + N_("Omit the frame pointer in leaf functions") }, \ + { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER, "" }, \ + { "stack-arg-probe", MASK_STACK_PROBE, \ + N_("Enable stack probing") }, \ + { "no-stack-arg-probe", -MASK_STACK_PROBE, "" }, \ + { "windows", 0, 0 /* undocumented */ }, \ + { "dll", 0, 0 /* undocumented */ }, \ + { "align-stringops", -MASK_NO_ALIGN_STROPS, \ + N_("Align destination of the string operations") }, \ + { "no-align-stringops", MASK_NO_ALIGN_STROPS, \ + N_("Do not align destination of the string operations") }, \ + { "inline-all-stringops", MASK_INLINE_ALL_STROPS, \ + N_("Inline all known string operations") }, \ + { "no-inline-all-stringops", -MASK_INLINE_ALL_STROPS, \ + N_("Do not inline all known string operations") }, \ + { "push-args", -MASK_NO_PUSH_ARGS, \ + N_("Use push instructions to save outgoing arguments") }, \ + { "no-push-args", MASK_NO_PUSH_ARGS, \ + N_("Do not use push instructions to save outgoing arguments") }, \ + { "accumulate-outgoing-args", (MASK_ACCUMULATE_OUTGOING_ARGS \ + | MASK_ACCUMULATE_OUTGOING_ARGS_SET), \ + N_("Use push instructions to save outgoing arguments") }, \ + { "no-accumulate-outgoing-args",MASK_ACCUMULATE_OUTGOING_ARGS_SET, \ + N_("Do not use push instructions to save outgoing arguments") }, \ + { "mmx", MASK_MMX | MASK_MMX_SET, \ + N_("Support MMX built-in functions") }, \ + { "no-mmx", -MASK_MMX, \ + N_("Do not support MMX built-in functions") }, \ + { "no-mmx", MASK_MMX_SET, N_("") }, \ + { "3dnow", MASK_3DNOW | MASK_3DNOW_SET, \ + N_("Support 3DNow! built-in functions") }, \ + { "no-3dnow", -MASK_3DNOW, N_("") }, \ + { "no-3dnow", MASK_3DNOW_SET, \ + N_("Do not support 3DNow! built-in functions") }, \ + { "sse", MASK_SSE | MASK_SSE_SET, \ + N_("Support MMX and SSE built-in functions and code generation") }, \ + { "no-sse", -MASK_SSE, N_("") }, \ + { "no-sse", MASK_SSE_SET, \ + N_("Do not support MMX and SSE built-in functions and code generation") },\ + { "sse2", MASK_SSE2 | MASK_SSE2_SET, \ + N_("Support MMX, SSE and SSE2 built-in functions and code generation") }, \ + { "no-sse2", -MASK_SSE2, N_("") }, \ + { "no-sse2", MASK_SSE2_SET, \ + N_("Do not support MMX, SSE and SSE2 built-in functions and code generation") }, \ + { "128bit-long-double", MASK_128BIT_LONG_DOUBLE, \ + N_("sizeof(long double) is 16") }, \ + { "96bit-long-double", -MASK_128BIT_LONG_DOUBLE, \ + N_("sizeof(long double) is 12") }, \ + { "64", MASK_64BIT, \ + N_("Generate 64bit x86-64 code") }, \ + { "32", -MASK_64BIT, \ + N_("Generate 32bit i386 code") }, \ + { "red-zone", -MASK_NO_RED_ZONE, \ + N_("Use red-zone in the x86-64 code") }, \ + { "no-red-zone", MASK_NO_RED_ZONE, \ + N_("Do not use red-zone in the x86-64 code") }, \ + SUBTARGET_SWITCHES \ + { "", TARGET_DEFAULT, 0 }} + +#ifdef TARGET_64BIT_DEFAULT +#define TARGET_DEFAULT (MASK_64BIT | TARGET_SUBTARGET_DEFAULT) +#else +#define TARGET_DEFAULT TARGET_SUBTARGET_DEFAULT +#endif /* 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_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" + PROCESSOR_K6, + PROCESSOR_ATHLON, + PROCESSOR_PENTIUM4, + PROCESSOR_max +}; +enum fpmath_unit +{ + FPMATH_387 = 1, + FPMATH_SSE = 2 +}; extern enum processor_type ix86_cpu; +extern enum fpmath_unit ix86_fpmath; 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. @@ -257,17 +417,35 @@ extern int ix86_arch; 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 \ +#define TARGET_OPTIONS \ +{ { "cpu=", &ix86_cpu_string, \ + N_("Schedule code for given CPU")}, \ + { "fpmath=", &ix86_fpmath_string, \ + N_("Generate floating point mathematics using given instruction set")},\ + { "arch=", &ix86_arch_string, \ + N_("Generate code for given CPU")}, \ + { "regparm=", &ix86_regparm_string, \ + N_("Number of registers used to pass integer arguments") }, \ + { "align-loops=", &ix86_align_loops_string, \ + N_("Loop code aligned to this power of 2") }, \ + { "align-jumps=", &ix86_align_jumps_string, \ + N_("Jump targets are aligned to this power of 2") }, \ + { "align-functions=", &ix86_align_funcs_string, \ + N_("Function starts are aligned to this power of 2") }, \ + { "preferred-stack-boundary=", \ + &ix86_preferred_stack_boundary_string, \ + N_("Attempt to keep stack aligned to this power of 2") }, \ + { "branch-cost=", &ix86_branch_cost_string, \ + N_("Branches are this expensive (1-5, arbitrary units)") }, \ + { "cmodel=", &ix86_cmodel_string, \ + N_("Use given x86-64 code model") }, \ + { "debug-arg", &ix86_debug_arg_string, \ + N_("" /* Undocumented. */) }, \ + { "debug-addr", &ix86_debug_addr_string, \ + N_("" /* Undocumented. */) }, \ + { "asm=", &ix86_asm_string, \ + N_("Use given assembler dialect") }, \ + SUBTARGET_OPTIONS \ } /* Sometimes certain combinations of command options do not make @@ -286,58 +464,176 @@ extern int ix86_arch; #define SUBTARGET_OPTIONS /* Define this to change the optimizations performed by default. */ -#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE) +#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}}" +%{m386:-mcpu=i386 \ +%n`-m386' is deprecated. Use `-march=i386' or `-mcpu=i386' instead.\n} \ +%{m486:-mcpu=i486 \ +%n`-m486' is deprecated. Use `-march=i486' or `-mcpu=i486' instead.\n} \ +%{mpentium:-mcpu=pentium \ +%n`-mpentium' is deprecated. Use `-march=pentium' or `-mcpu=pentium' instead.\n} \ +%{mpentiumpro:-mcpu=pentiumpro \ +%n`-mpentiumpro' is deprecated. Use `-march=pentiumpro' or `-mcpu=pentiumpro' instead.\n}} \ +%{mintel-syntax:-masm=intel \ +%n`-mintel-syntax' is deprecated. Use `-masm=intel' instead.\n} \ +%{mno-intel-syntax:-masm=att \ +%n`-mno-intel-syntax' is deprecated. Use `-masm=att' instead.\n}" #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__" - +#define TARGET_CPU_DEFAULT_i386 0 +#define TARGET_CPU_DEFAULT_i486 1 +#define TARGET_CPU_DEFAULT_pentium 2 +#define TARGET_CPU_DEFAULT_pentium_mmx 3 +#define TARGET_CPU_DEFAULT_pentiumpro 4 +#define TARGET_CPU_DEFAULT_pentium2 5 +#define TARGET_CPU_DEFAULT_pentium3 6 +#define TARGET_CPU_DEFAULT_pentium4 7 +#define TARGET_CPU_DEFAULT_k6 8 +#define TARGET_CPU_DEFAULT_k6_2 9 +#define TARGET_CPU_DEFAULT_k6_3 10 +#define TARGET_CPU_DEFAULT_athlon 11 +#define TARGET_CPU_DEFAULT_athlon_sse 12 + +#define TARGET_CPU_DEFAULT_NAMES {"i386", "i486", "pentium", "pentium-mmx",\ + "pentiumpro", "pentium2", "pentium3", \ + "pentium4", "k6", "k6-2", "k6-3",\ + "athlon", "athlon-4"} #ifndef CPP_CPU_DEFAULT_SPEC -#if TARGET_CPU_DEFAULT == 1 -#define CPP_CPU_DEFAULT_SPEC "%(cpp_486)" +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_i486 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i486__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i586__ -D__tune_pentium__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium_mmx +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i586__ -D__tune_pentium__ -D__tune_pentium_mmx__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentiumpro +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium2 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__\ +-D__tune_pentium2__" #endif -#if TARGET_CPU_DEFAULT == 2 -#define CPP_CPU_DEFAULT_SPEC "%(cpp_586)" +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium3 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i686__ -D__tune_pentiumpro__\ +-D__tune_pentium2__ -D__tune_pentium3__" #endif -#if TARGET_CPU_DEFAULT == 3 -#define CPP_CPU_DEFAULT_SPEC "%(cpp_686)" +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_pentium4 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_pentium4__" #endif -#if TARGET_CPU_DEFAULT == 4 -#define CPP_CPU_DEFAULT_SPEC "%(cpp_k6)" +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6_2 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__ -D__tune_k6_2__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_k6_3 +#define CPP_CPU_DEFAULT_SPEC "-D__tune_k6__ -D__tune_k6_3__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_athlon +#define CPP_CPU_DEFAULT_SPEC "-D__tune_athlon__" +#endif +#if TARGET_CPU_DEFAULT == TARGET_CPU_DEFAULT_athlon_sse +#define CPP_CPU_DEFAULT_SPEC "-D__tune_athlon__ -D__tune_athlon_sse__" #endif #ifndef CPP_CPU_DEFAULT_SPEC -#define CPP_CPU_DEFAULT_SPEC "" +#define CPP_CPU_DEFAULT_SPEC "-D__tune_i386__" #endif #endif /* CPP_CPU_DEFAULT_SPEC */ +#ifdef TARGET_BI_ARCH +#define NO_BUILTIN_SIZE_TYPE +#define NO_BUILTIN_PTRDIFF_TYPE +#endif + +#ifdef NO_BUILTIN_SIZE_TYPE +#define CPP_CPU32_SIZE_TYPE_SPEC \ + " -D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int" +#define CPP_CPU64_SIZE_TYPE_SPEC \ + " -D__SIZE_TYPE__=unsigned\\ long\\ int -D__PTRDIFF_TYPE__=long\\ int" +#else +#define CPP_CPU32_SIZE_TYPE_SPEC "" +#define CPP_CPU64_SIZE_TYPE_SPEC "" +#endif + +#define CPP_CPU32_SPEC \ + "-Acpu=i386 -Amachine=i386 %{!ansi:%{!std=c*:%{!std=i*:-Di386}}} -D__i386 \ +-D__i386__ %(cpp_cpu32sizet)" + +#define CPP_CPU64_SPEC \ + "-Acpu=x86_64 -Amachine=x86_64 -D__x86_64 -D__x86_64__ %(cpp_cpu64sizet)" + +#define CPP_CPUCOMMON_SPEC "\ +%{march=i386:%{!mcpu*:-D__tune_i386__ }}\ +%{march=i486:-D__i486 -D__i486__ %{!mcpu*:-D__tune_i486__ }}\ +%{march=pentium|march=i586:-D__i586 -D__i586__ -D__pentium -D__pentium__ \ + %{!mcpu*:-D__tune_i586__ -D__tune_pentium__ }}\ +%{march=pentium-mmx:-D__i586 -D__i586__ -D__pentium -D__pentium__ \ + -D__pentium__mmx__ \ + %{!mcpu*:-D__tune_i586__ -D__tune_pentium__ -D__tune_pentium_mmx__}}\ +%{march=pentiumpro|march=i686:-D__i686 -D__i686__ \ + -D__pentiumpro -D__pentiumpro__ \ + %{!mcpu*:-D__tune_i686__ -D__tune_pentiumpro__ }}\ +%{march=k6:-D__k6 -D__k6__ %{!mcpu*:-D__tune_k6__ }}\ +%{march=k6-2:-D__k6 -D__k6__ -D__k6_2__ \ + %{!mcpu*:-D__tune_k6__ -D__tune_k6_2__ }}\ +%{march=k6-3:-D__k6 -D__k6__ -D__k6_3__ \ + %{!mcpu*:-D__tune_k6__ -D__tune_k6_3__ }}\ +%{march=athlon|march=athlon-tbird:-D__athlon -D__athlon__ \ + %{!mcpu*:-D__tune_athlon__ }}\ +%{march=athlon-4|march=athlon-xp|march=athlon-mp:-D__athlon -D__athlon__ \ + -D__athlon_sse__ \ + %{!mcpu*:-D__tune_athlon__ -D__tune_athlon_sse__ }}\ +%{march=pentium4:-D__pentium4 -D__pentium4__ %{!mcpu*:-D__tune_pentium4__ }}\ +%{m386|mcpu=i386:-D__tune_i386__ }\ +%{m486|mcpu=i486:-D__tune_i486__ }\ +%{mpentium|mcpu=pentium|mcpu=i586|mcpu=pentium-mmx:-D__tune_i586__ -D__tune_pentium__ }\ +%{mpentiumpro|mcpu=pentiumpro|mcpu=i686|cpu=pentium2|cpu=pentium3:-D__tune_i686__ \ +-D__tune_pentiumpro__ }\ +%{mcpu=k6|mcpu=k6-2|mcpu=k6-3:-D__tune_k6__ }\ +%{mcpu=athlon|mcpu=athlon-tbird|mcpu=athlon-4|mcpu=athlon-xp|mcpu=athlon-mp:\ +-D__tune_athlon__ }\ +%{mcpu=athlon-4|mcpu=athlon-xp|mcpu=athlon-mp:\ +-D__tune_athlon_sse__ }\ +%{mcpu=pentium4:-D__tune_pentium4__ }\ +%{march=athlon-tbird|march=athlon-xp|march=athlon-mp|march=pentium3|march=pentium4:\ +-D__SSE__ }\ +%{march=pentium-mmx|march=k6|march=k6-2|march=k6-3\ +march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\ +|march=athlon-mp|march=pentium2|march=pentium3|march=pentium4: -D__MMX__ }\ +%{march=k6-2|march=k6-3\ +march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\ +|march=athlon-mp: -D__3dNOW__ }\ +%{march=athlon|march=athlon-tbird|march=athlon-4|march=athlon-xp\ +|march=athlon-mp: -D__3dNOW_A__ }\ +%{march=pentium4: -D__SSE2__ }\ +%{!march*:%{!mcpu*:%{!m386:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}}}" + #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)}}}" +#ifdef TARGET_BI_ARCH +#ifdef TARGET_64BIT_DEFAULT +#define CPP_CPU_SPEC "%{m32:%(cpp_cpu32)}%{!m32:%(cpp_cpu64)} %(cpp_cpucommon)" +#else +#define CPP_CPU_SPEC "%{m64:%(cpp_cpu64)}%{!m64:%(cpp_cpu32)} %(cpp_cpucommon)" +#endif +#else +#ifdef TARGET_64BIT_DEFAULT +#define CPP_CPU_SPEC "%(cpp_cpu64) %(cpp_cpucommon)" +#else +#define CPP_CPU_SPEC "%(cpp_cpu32) %(cpp_cpucommon)" +#endif +#endif #endif #ifndef CC1_SPEC -#define CC1_SPEC "%(cc1_spec) " +#define CC1_SPEC "%(cc1_cpu) " #endif /* This macro defines names of additional specifications to put in the @@ -355,24 +651,55 @@ extern int ix86_arch; #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 }, \ + { "cpp_cpu32", CPP_CPU32_SPEC }, \ + { "cpp_cpu64", CPP_CPU64_SPEC }, \ + { "cpp_cpu32sizet", CPP_CPU32_SIZE_TYPE_SPEC }, \ + { "cpp_cpu64sizet", CPP_CPU64_SIZE_TYPE_SPEC }, \ + { "cpp_cpucommon", CPP_CPUCOMMON_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 for XFmode or TFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. + + The XFmode is specified by i386 ABI, while TFmode may be faster + due to alignment and simplifications in the address calculations. + */ +#define LONG_DOUBLE_TYPE_SIZE (TARGET_128BIT_LONG_DOUBLE ? 128 : 96) +#define MAX_LONG_DOUBLE_TYPE_SIZE 128 +#ifdef __x86_64__ +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128 +#else +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 96 +#endif +/* Tell real.c that this is the 80-bit Intel extended float format + packaged in a 128-bit or 96bit entity. */ +#define INTEL_EXTENDED_IEEE_FORMAT 1 + + +#define SHORT_TYPE_SIZE 16 +#define INT_TYPE_SIZE 32 +#define FLOAT_TYPE_SIZE 32 +#define LONG_TYPE_SIZE BITS_PER_WORD +#define MAX_WCHAR_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE 64 +#define LONG_LONG_TYPE_SIZE 64 + +#if defined (TARGET_BI_ARCH) || defined (TARGET_64BIT_DEFAULT) +#define MAX_BITS_PER_WORD 64 +#define MAX_LONG_TYPE_SIZE 64 +#else +#define MAX_BITS_PER_WORD 32 +#define MAX_LONG_TYPE_SIZE 32 +#endif /* 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. */ + decimal <-> binary conversion. */ /* #define REAL_ARITHMETIC */ /* Define this if most significant byte of a word is the lowest numbered. */ @@ -396,46 +723,68 @@ extern int ix86_arch; 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 +#define BITS_PER_WORD (TARGET_64BIT ? 64 : 32) /* Width of a word, in units (bytes). */ -#define UNITS_PER_WORD 4 +#define UNITS_PER_WORD (TARGET_64BIT ? 8 : 4) +#define MIN_UNITS_PER_WORD 4 /* Width in bits of a pointer. See also the macro `Pmode' defined below. */ -#define POINTER_SIZE 32 +#define POINTER_SIZE BITS_PER_WORD /* Allocation boundary (in *bits*) for storing arguments in argument list. */ -#define PARM_BOUNDARY 32 +#define PARM_BOUNDARY BITS_PER_WORD -/* Boundary (in *bits*) on which the stack pointer must be aligned. */ -#define STACK_BOUNDARY 32 +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY BITS_PER_WORD /* 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 +#define PREFERRED_STACK_BOUNDARY ix86_preferred_stack_boundary + +/* As of July 2001, many runtimes to not align the stack properly when + entering main. This causes expand_main_function to forcably align + the stack, which results in aligned frames for functions called from + main, though it does nothing for the alignment of main itself. */ +#define FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN \ + (ix86_preferred_stack_boundary > STACK_BOUNDARY && !TARGET_64BIT) -/* 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)) +/* Allocation boundary for the code of a function. */ +#define FUNCTION_BOUNDARY 16 -/* Alignment of field after `int : 0' in a structure. */ +/* Alignment of field after `int : 0' in a structure. */ -#define EMPTY_FIELD_BOUNDARY 32 +#define EMPTY_FIELD_BOUNDARY BITS_PER_WORD /* 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) + rounder than this. + + Pentium+ preferrs DFmode values to be aligned to 64 bit boundary + and Pentium Pro XFmode values at 128 bit boundaries. */ + +#define BIGGEST_ALIGNMENT 128 + +/* Decide whether a variable of mode MODE must be 128 bit aligned. */ +#define ALIGN_MODE_128(MODE) \ + ((MODE) == XFmode || (MODE) == TFmode || ((MODE) == TImode) \ + || (MODE) == V4SFmode || (MODE) == V4SImode) + +/* The published ABIs say that doubles should be aligned on word + boundaries, so lower the aligment for structure fields unless + -malign-double is set. */ +/* BIGGEST_FIELD_ALIGNMENT is also used in libobjc, where it must be + constant. Use the smaller value in that context. */ +#ifndef IN_TARGET_LIBS +#define BIGGEST_FIELD_ALIGNMENT (TARGET_64BIT ? 128 : (TARGET_ALIGN_DOUBLE ? 64 : 32)) +#else +#define BIGGEST_FIELD_ALIGNMENT 32 +#endif /* If defined, a C expression to compute the alignment given to a - constant that is being placed in memory. CONSTANT is the constant + constant that is being placed in memory. EXP 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. @@ -446,18 +795,7 @@ extern int ix86_arch; 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)) +#define CONSTANT_ALIGNMENT(EXP, ALIGN) ix86_constant_alignment ((EXP), (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 @@ -471,41 +809,7 @@ extern int ix86_arch; 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)) +#define DATA_ALIGNMENT(TYPE, ALIGN) ix86_data_alignment ((TYPE), (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 @@ -517,35 +821,14 @@ extern int ix86_arch; 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)) +#define LOCAL_ALIGNMENT(TYPE, ALIGN) ix86_local_alignment ((TYPE), (ALIGN)) + +/* If defined, a C expression that gives the alignment boundary, in + bits, of an argument with the specified mode and type. If it is + not defined, `PARM_BOUNDARY' is used for all arguments. */ + +#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \ + ix86_function_arg_boundary ((MODE), (TYPE)) /* Set this non-zero if move instructions will actually fail to work when given unaligned data. */ @@ -555,28 +838,16 @@ extern int ix86_arch; 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. */ + for details. */ #define STACK_REGS -#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode) +#define IS_STACK_MODE(MODE) \ + ((MODE) == DFmode || (MODE) == SFmode || (MODE) == XFmode \ + || (MODE) == TFmode) /* Number of actual hardware registers. The hardware registers are assigned numbers for the compiler @@ -592,27 +863,62 @@ extern int ix86_arch; 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. */ + pointer. */ + +#define FIRST_PSEUDO_REGISTER 53 + +/* Number of hardware registers that go into the DWARF-2 unwind info. + If not defined, equals FIRST_PSEUDO_REGISTER. */ -#define FIRST_PSEUDO_REGISTER 17 +#define DWARF_FRAME_REGISTERS 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 } + On the 80386, the stack pointer is such, as is the arg pointer. + + The value is an mask - bit 1 is set for fixed registers + for 32bit target, while 2 is set for fixed registers for 64bit. + Proper value is computed in the CONDITIONAL_REGISTER_USAGE. + */ +#define FIXED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \ +{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, \ +/*arg,flags,fpsr,dir,frame*/ \ + 3, 3, 3, 3, 3, \ +/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ +/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ +/* r8, r9, r10, r11, r12, r13, r14, r15*/ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ +/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \ + 1, 1, 1, 1, 1, 1, 1, 1} + /* 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any registers that can be used without being saved. The latter must include the registers where values are returned and the register where structure-value addresses are passed. - Aside from that, you can include as many other registers as you like. */ - -#define CALL_USED_REGISTERS \ -/*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 } + Aside from that, you can include as many other registers as you like. + + The value is an mask - bit 1 is set for call used + for 32bit target, while 2 is set for call used for 64bit. + Proper value is computed in the CONDITIONAL_REGISTER_USAGE. +*/ +#define CALL_USED_REGISTERS \ +/*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ \ +{ 3, 3, 3, 0, 2, 2, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, \ +/*arg,flags,fpsr,dir,frame*/ \ + 3, 3, 3, 3, 3, \ +/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \ + 3, 3, 3, 3, 3, 3, 3, 3, \ +/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \ + 3, 3, 3, 3, 3, 3, 3, 3, \ +/* r8, r9, r10, r11, r12, r13, r14, r15*/ \ + 3, 3, 3, 3, 1, 1, 1, 1, \ +/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \ + 3, 3, 3, 3, 3, 3, 3, 3} \ /* Order in which to allocate registers. Each register must be listed once, even those in FIXED_REGISTERS. List frame pointer @@ -631,45 +937,67 @@ extern int ix86_arch; 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 () + generated by allocating edx first, so restore the 'natural' order of things. */ + +#define REG_ALLOC_ORDER \ +/*ax,dx,cx,*/ \ +{ 0, 1, 2, \ +/* bx,si,di,bp,sp,*/ \ + 3, 4, 5, 6, 7, \ +/*r8,r9,r10,r11,*/ \ + 37,38, 39, 40, \ +/*r12,r15,r14,r13*/ \ + 41, 44, 43, 42, \ +/*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/ \ + 21, 22, 23, 24, 25, 26, 27, 28, \ +/*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/ \ + 45, 46, 47, 48, 49, 50, 51, 52, \ +/*st,st1,st2,st3,st4,st5,st6,st7*/ \ + 8, 9, 10, 11, 12, 13, 14, 15, \ +/*,arg,cc,fpsr,dir,frame*/ \ + 16,17, 18, 19, 20, \ +/*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/ \ + 29, 30, 31, 32, 33, 34, 35, 36 } /* 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; \ - } \ - } +#define CONDITIONAL_REGISTER_USAGE \ +do { \ + int i; \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + fixed_regs[i] = (fixed_regs[i] & (TARGET_64BIT ? 2 : 1)) != 0; \ + call_used_regs[i] = (call_used_regs[i] \ + & (TARGET_64BIT ? 2 : 1)) != 0; \ + } \ + if (flag_pic) \ + { \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ + } \ + if (! TARGET_MMX) \ + { \ + int i; \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i)) \ + fixed_regs[i] = call_used_regs[i] = 1; \ + } \ + if (! TARGET_SSE) \ + { \ + int i; \ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ + if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i)) \ + fixed_regs[i] = call_used_regs[i] = 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; \ + } \ + } while (0) /* Return number of consecutive hard regs needed starting at reg REGNO to hold something of mode MODE. @@ -682,25 +1010,48 @@ extern int ix86_arch; */ #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) + (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) \ + ? (COMPLEX_MODE_P (MODE) ? 2 : 1) \ + : ((MODE) == TFmode \ + ? (TARGET_64BIT ? 2 : 3) \ + : (MODE) == TCmode \ + ? (TARGET_64BIT ? 4 : 6) \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))) + +#define VALID_SSE_REG_MODE(MODE) \ + ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode \ + || (MODE) == SFmode \ + || (TARGET_SSE2 && ((MODE) == DFmode || VALID_MMX_REG_MODE (MODE)))) + +#define VALID_MMX_REG_MODE_3DNOW(MODE) \ + ((MODE) == V2SFmode || (MODE) == SFmode) + +#define VALID_MMX_REG_MODE(MODE) \ + ((MODE) == DImode || (MODE) == V8QImode || (MODE) == V4HImode \ + || (MODE) == V2SImode || (MODE) == SImode) + +#define VECTOR_MODE_SUPPORTED_P(MODE) \ + (VALID_SSE_REG_MODE (MODE) && TARGET_SSE ? 1 \ + : VALID_MMX_REG_MODE (MODE) && TARGET_MMX ? 1 \ + : VALID_MMX_REG_MODE_3DNOW (MODE) && TARGET_3DNOW ? 1 : 0) + +#define VALID_FP_MODE_P(MODE) \ + ((MODE) == SFmode || (MODE) == DFmode || (MODE) == TFmode \ + || (!TARGET_64BIT && (MODE) == XFmode) \ + || (MODE) == SCmode || (MODE) == DCmode || (MODE) == TCmode \ + || (!TARGET_64BIT && (MODE) == XCmode)) + +#define VALID_INT_MODE_P(MODE) \ + ((MODE) == QImode || (MODE) == HImode || (MODE) == SImode \ + || (MODE) == DImode \ + || (MODE) == CQImode || (MODE) == CHImode || (MODE) == CSImode \ + || (MODE) == CDImode \ + || (TARGET_64BIT && ((MODE) == TImode || (MODE) == CTImode))) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ix86_hard_regno_mode_ok ((REGNO), (MODE)) /* Value is 1 if it is a good idea to tie two pseudo registers when one has mode MODE1 and one has mode MODE2. @@ -709,9 +1060,28 @@ extern int ix86_arch; #define MODES_TIEABLE_P(MODE1, MODE2) \ ((MODE1) == (MODE2) \ - || ((MODE1) == SImode && (MODE2) == HImode) \ - || ((MODE1) == HImode && (MODE2) == SImode)) - + || (((MODE1) == HImode || (MODE1) == SImode \ + || ((MODE1) == QImode \ + && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \ + || ((MODE1) == DImode && TARGET_64BIT)) \ + && ((MODE2) == HImode || (MODE2) == SImode \ + || ((MODE1) == QImode \ + && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \ + || ((MODE2) == DImode && TARGET_64BIT)))) + + +/* Specify the modes required to caller save a given hard regno. + We do this on i386 to prevent flags from being saved at all. + + Kill any attempts to combine saving of modes. */ + +#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ + (CC_REGNO_P (REGNO) ? VOIDmode \ + : (MODE) == VOIDmode && (NREGS) != 1 ? VOIDmode \ + : (MODE) == VOIDmode ? choose_hard_reg_mode ((REGNO), (NREGS)) \ + : (MODE) == HImode && !TARGET_PARTIAL_REG_STALL ? SImode \ + : (MODE) == QImode && (REGNO) >= 4 && !TARGET_64BIT ? SImode \ + : (MODE)) /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ @@ -723,7 +1093,10 @@ extern int ix86_arch; #define STACK_POINTER_REGNUM 7 /* Base register for access to local variables of the function. */ -#define FRAME_POINTER_REGNUM 6 +#define HARD_FRAME_POINTER_REGNUM 6 + +/* Base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM 20 /* First floating point reg */ #define FIRST_FLOAT_REG 8 @@ -732,21 +1105,51 @@ extern int ix86_arch; #define FIRST_STACK_REG FIRST_FLOAT_REG #define LAST_STACK_REG (FIRST_FLOAT_REG + 7) +#define FLAGS_REG 17 +#define FPSR_REG 18 +#define DIRFLAG_REG 19 + +#define FIRST_SSE_REG (FRAME_POINTER_REGNUM + 1) +#define LAST_SSE_REG (FIRST_SSE_REG + 7) + +#define FIRST_MMX_REG (LAST_SSE_REG + 1) +#define LAST_MMX_REG (FIRST_MMX_REG + 7) + +#define FIRST_REX_INT_REG (LAST_MMX_REG + 1) +#define LAST_REX_INT_REG (FIRST_REX_INT_REG + 7) + +#define FIRST_REX_SSE_REG (LAST_REX_INT_REG + 1) +#define LAST_REX_SSE_REG (FIRST_REX_SSE_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 ()) +#define FRAME_POINTER_REQUIRED ix86_frame_pointer_required () + +/* Override this in other tm.h files to cope with various OS losage + requiring a frame pointer. */ +#ifndef SUBTARGET_FRAME_POINTER_REQUIRED +#define SUBTARGET_FRAME_POINTER_REQUIRED 0 +#endif + +/* Make sure we can access arbitrary call frames. */ +#define SETUP_FRAME_ADDRESSES() ix86_setup_frame_addresses () /* 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 in which static-chain is passed to a function. + We do use ECX as static chain register for 32 bit ABI. On the + 64bit ABI, ECX is an argument register, so we use R10 instead. */ +#define STATIC_CHAIN_REGNUM (TARGET_64BIT ? FIRST_REX_INT_REG + 10 - 8 : 2) /* Register to hold the addressing base for position independent - code access to data items. */ -#define PIC_OFFSET_TABLE_REGNUM 3 + code access to data items. + We don't use PIC pointer for 64bit mode. Define the regnum to + dummy value to prevent gcc from pessimizing code dealing with EBX. + */ +#define PIC_OFFSET_TABLE_REGNUM (TARGET_64BIT ? INVALID_REGNUM : 3) /* Register in which address to store a structure value arrives in the function. On the 386, the prologue @@ -775,7 +1178,7 @@ extern int ix86_arch; `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */ #define RETURN_IN_MEMORY(TYPE) \ - ((TYPE_MODE (TYPE) == BLKmode) || int_size_in_bytes (TYPE) > 12) + ix86_return_in_memory (TYPE) /* Define the classes of registers for register constraints in the @@ -800,55 +1203,105 @@ extern int ix86_arch; 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. */ + and the "b" register constraint is useful in asms for syscalls. + + The flags and fpsr registers are in no class. */ enum reg_class { NO_REGS, - AREG, DREG, CREG, BREG, + AREG, DREG, CREG, BREG, SIREG, DIREG, AD_REGS, /* %eax/%edx for DImode */ Q_REGS, /* %eax %ebx %ecx %edx */ - SIREG, DIREG, + NON_Q_REGS, /* %esi %edi %ebp %esp */ INDEX_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp */ - GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */ + LEGACY_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */ + GENERAL_REGS, /* %eax %ebx %ecx %edx %esi %edi %ebp %esp %r8 - %r15*/ FP_TOP_REG, FP_SECOND_REG, /* %st(0) %st(1) */ FLOAT_REGS, + SSE_REGS, + MMX_REGS, + FP_TOP_SSE_REGS, + FP_SECOND_SSE_REGS, + FLOAT_SSE_REGS, + FLOAT_INT_REGS, + INT_SSE_REGS, + FLOAT_INT_SSE_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)) +#define N_REG_CLASSES ((int) LIM_REG_CLASSES) + +#define INTEGER_CLASS_P(CLASS) \ + reg_class_subset_p ((CLASS), GENERAL_REGS) +#define FLOAT_CLASS_P(CLASS) \ + reg_class_subset_p ((CLASS), FLOAT_REGS) +#define SSE_CLASS_P(CLASS) \ + reg_class_subset_p ((CLASS), SSE_REGS) +#define MMX_CLASS_P(CLASS) \ + reg_class_subset_p ((CLASS), MMX_REGS) +#define MAYBE_INTEGER_CLASS_P(CLASS) \ + reg_classes_intersect_p ((CLASS), GENERAL_REGS) +#define MAYBE_FLOAT_CLASS_P(CLASS) \ + reg_classes_intersect_p ((CLASS), FLOAT_REGS) +#define MAYBE_SSE_CLASS_P(CLASS) \ + reg_classes_intersect_p (SSE_REGS, (CLASS)) +#define MAYBE_MMX_CLASS_P(CLASS) \ + reg_classes_intersect_p (MMX_REGS, (CLASS)) + +#define Q_CLASS_P(CLASS) \ + reg_class_subset_p ((CLASS), Q_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", \ + "AD_REGS", \ + "Q_REGS", "NON_Q_REGS", \ "INDEX_REGS", \ + "LEGACY_REGS", \ "GENERAL_REGS", \ "FP_TOP_REG", "FP_SECOND_REG", \ "FLOAT_REGS", \ + "SSE_REGS", \ + "MMX_REGS", \ + "FP_TOP_SSE_REGS", \ + "FP_SECOND_SSE_REGS", \ + "FLOAT_SSE_REGS", \ + "FLOAT_INT_REGS", \ + "INT_SSE_REGS", \ + "FLOAT_INT_SSE_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}} +#define REG_CLASS_CONTENTS \ +{ { 0x00, 0x0 }, \ + { 0x01, 0x0 }, { 0x02, 0x0 }, /* AREG, DREG */ \ + { 0x04, 0x0 }, { 0x08, 0x0 }, /* CREG, BREG */ \ + { 0x10, 0x0 }, { 0x20, 0x0 }, /* SIREG, DIREG */ \ + { 0x03, 0x0 }, /* AD_REGS */ \ + { 0x0f, 0x0 }, /* Q_REGS */ \ + { 0x1100f0, 0x1fe0 }, /* NON_Q_REGS */ \ + { 0x7f, 0x1fe0 }, /* INDEX_REGS */ \ + { 0x1100ff, 0x0 }, /* LEGACY_REGS */ \ + { 0x1100ff, 0x1fe0 }, /* GENERAL_REGS */ \ + { 0x100, 0x0 }, { 0x0200, 0x0 },/* FP_TOP_REG, FP_SECOND_REG */\ + { 0xff00, 0x0 }, /* FLOAT_REGS */ \ +{ 0x1fe00000,0x1fe000 }, /* SSE_REGS */ \ +{ 0xe0000000, 0x1f }, /* MMX_REGS */ \ +{ 0x1fe00100,0x1fe000 }, /* FP_TOP_SSE_REG */ \ +{ 0x1fe00200,0x1fe000 }, /* FP_SECOND_SSE_REG */ \ +{ 0x1fe0ff00,0x1fe000 }, /* FLOAT_SSE_REGS */ \ + { 0x1ffff, 0x1fe0 }, /* FLOAT_INT_REGS */ \ +{ 0x1fe100ff,0x1fffe0 }, /* INT_SSE_REGS */ \ +{ 0x1fe1ffff,0x1fffe0 }, /* FLOAT_INT_SSE_REGS */ \ +{ 0xffffffff,0x1fffff } \ +} /* The same information, inverted: Return the class number of the smallest class containing @@ -859,30 +1312,62 @@ enum reg_class /* 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. */ + extending the lifetime of these registers. */ #define SMALL_REGISTER_CLASSES 1 #define QI_REG_P(X) \ (REG_P (X) && REGNO (X) < 4) + +#define GENERAL_REGNO_P(N) \ + ((N) < 8 || REX_INT_REGNO_P (N)) + +#define GENERAL_REG_P(X) \ + (REG_P (X) && GENERAL_REGNO_P (REGNO (X))) + +#define ANY_QI_REG_P(X) (TARGET_64BIT ? GENERAL_REG_P(X) : QI_REG_P (X)) + #define NON_QI_REG_P(X) \ (REG_P (X) && REGNO (X) >= 4 && REGNO (X) < FIRST_PSEUDO_REGISTER) +#define REX_INT_REGNO_P(N) ((N) >= FIRST_REX_INT_REG && (N) <= LAST_REX_INT_REG) +#define REX_INT_REG_P(X) (REG_P (X) && REX_INT_REGNO_P (REGNO (X))) + #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 FP_REGNO_P(N) ((N) >= FIRST_STACK_REG && (N) <= LAST_STACK_REG) +#define ANY_FP_REG_P(X) (REG_P (X) && ANY_FP_REGNO_P (REGNO (X))) +#define ANY_FP_REGNO_P(N) (FP_REGNO_P (N) || SSE_REGNO_P (N)) + +#define SSE_REGNO_P(N) \ + (((N) >= FIRST_SSE_REG && (N) <= LAST_SSE_REG) \ + || ((N) >= FIRST_REX_SSE_REG && (N) <= LAST_REX_SSE_REG)) + +#define SSE_REGNO(N) \ + ((N) < 8 ? FIRST_SSE_REG + (N) : FIRST_REX_SSE_REG + (N) - 8) +#define SSE_REG_P(N) (REG_P (N) && SSE_REGNO_P (REGNO (N))) + +#define SSE_FLOAT_MODE_P(MODE) \ + ((TARGET_SSE_MATH && (MODE) == SFmode) || (TARGET_SSE2 && (MODE) == DFmode)) + +#define MMX_REGNO_P(N) ((N) >= FIRST_MMX_REG && (N) <= LAST_MMX_REG) +#define MMX_REG_P(XOP) (REG_P (XOP) && MMX_REGNO_P (REGNO (XOP))) -#define STACK_REG_P(xop) (REG_P (xop) && \ - REGNO (xop) >= FIRST_STACK_REG && \ - REGNO (xop) <= 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 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) +#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 CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) +#define CC_REGNO_P(X) ((X) == FLAGS_REG || (X) == FPSR_REG) -/* #define OVERLAPPING_REGNO_P(REGNO) FP_REGNO_P (REGNO) */ +/* Indicate whether hard register numbered REG_NO should be converted + to SSA form. */ +#define CONVERT_HARD_REGISTER_TO_SSA_P(REG_NO) \ + ((REG_NO) == FLAGS_REG || (REG_NO) == ARG_POINTER_REGNUM) /* The class value for index registers, and the one for base regs. */ @@ -893,7 +1378,9 @@ enum reg_class #define REG_CLASS_FROM_LETTER(C) \ ((C) == 'r' ? GENERAL_REGS : \ - (C) == 'q' ? Q_REGS : \ + (C) == 'R' ? LEGACY_REGS : \ + (C) == 'q' ? TARGET_64BIT ? GENERAL_REGS : Q_REGS : \ + (C) == 'Q' ? Q_REGS : \ (C) == 'f' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ ? FLOAT_REGS \ : NO_REGS) : \ @@ -907,6 +1394,9 @@ enum reg_class (C) == 'b' ? BREG : \ (C) == 'c' ? CREG : \ (C) == 'd' ? DREG : \ + (C) == 'x' ? TARGET_SSE ? SSE_REGS : NO_REGS : \ + (C) == 'Y' ? TARGET_SSE2? SSE_REGS : NO_REGS : \ + (C) == 'y' ? TARGET_MMX ? MMX_REGS : NO_REGS : \ (C) == 'A' ? AD_REGS : \ (C) == 'D' ? DIREG : \ (C) == 'S' ? SIREG : NO_REGS) @@ -919,19 +1409,20 @@ enum reg_class I is for non-DImode shifts. J is for DImode shifts. - K and L are for an `andsi' optimization. + K is for signed imm8 operands. + L is for andsi as zero-extending move. M is for shifts that can be executed by the "lea" opcode. + N is for immedaite operands for out/in instructions (0-255) */ -#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) +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 \ + : (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 \ + : (C) == 'K' ? (VALUE) >= -128 && (VALUE) <= 127 \ + : (C) == 'L' ? (VALUE) == 0xff || (VALUE) == 0xffff \ + : (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 \ + : (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 \ + : 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 @@ -939,14 +1430,34 @@ enum reg_class 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) + ((C) == 'G' ? standard_80387_constant_p (VALUE) \ + : ((C) == 'H' ? standard_sse_constant_p (VALUE) : 0)) + +/* A C expression that defines the optional machine-dependent + constraint letters that can be used to segregate specific types of + operands, usually memory references, for the target machine. Any + letter that is not elsewhere defined and not matched by + `REG_CLASS_FROM_LETTER' may be used. Normally this macro will not + be defined. + + If it is required for a particular target machine, it should + return 1 if VALUE corresponds to the operand type represented by + the constraint letter C. If C is not defined as an extra + constraint, the value returned should be 0 regardless of VALUE. */ + +#define EXTRA_CONSTRAINT(VALUE, C) \ + ((C) == 'e' ? x86_64_sign_extended_value (VALUE) \ + : (C) == 'Z' ? x86_64_zero_extended_value (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. */ + register for which class CLASS would ordinarily be used. */ -#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ - ((MODE) == QImode && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS) \ +#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ + ((MODE) == QImode && !TARGET_64BIT \ + && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS \ + || (CLASS) == LEGACY_REGS || (CLASS) == INDEX_REGS) \ ? Q_REGS : (CLASS)) /* Given an rtx X being reloaded into a reg required to be @@ -960,32 +1471,37 @@ enum reg_class /* 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)) + movdf to do mem-to-mem moves through integer regs. */ + +#define PREFERRED_RELOAD_CLASS(X, CLASS) \ + ix86_preferred_reload_class ((X), (CLASS)) /* If we are copying between general and FP registers, we need a memory - location. */ + location. The same is true for SSE and MMX registers. */ +#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \ + ix86_secondary_memory_needed ((CLASS1), (CLASS2), (MODE), 1) + +/* QImode spills from non-QI registers need a scratch. This does not + happen often -- the only example so far requires an uninitialized + pseudo. */ -#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \ - ((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \ - || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, OUT) \ + (((CLASS) == GENERAL_REGS || (CLASS) == LEGACY_REGS \ + || (CLASS) == INDEX_REGS) && !TARGET_64BIT && (MODE) == QImode \ + ? Q_REGS : NO_REGS) /* 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)) + except in the FP regs, where a single reg is always enough. + The TFmodes are really just 80bit values, so we use only 3 registers + to hold them, instead of 4, as the size would suggest. + */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + (!MAYBE_INTEGER_CLASS_P (CLASS) \ + ? (COMPLEX_MODE_P (MODE) ? 2 : 1) \ + : ((GET_MODE_SIZE ((MODE) == TFmode ? XFmode : (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 @@ -1012,6 +1528,21 @@ enum reg_class || ((CLASS) == SIREG) \ || ((CLASS) == DIREG)) +/* A C statement that adds to CLOBBERS any hard regs the port wishes + to automatically clobber for all asms. + + We do this in the new i386 backend to maintain source compatibility + with the old cc0-based compiler. */ + +#define MD_ASM_CLOBBERS(CLOBBERS) \ + do { \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (5, "flags"), \ + (CLOBBERS)); \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (4, "fpsr"), \ + (CLOBBERS)); \ + (CLOBBERS) = tree_cons (NULL_TREE, build_string (7, "dirflag"), \ + (CLOBBERS)); \ + } while (0) /* Stack layout; function entry, exit and calling. */ @@ -1035,13 +1566,61 @@ enum reg_class 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. */ + has the effect of rounding up to 2. + + For 64bit ABI we round up to 8 bytes. + */ + +#define PUSH_ROUNDING(BYTES) \ + (TARGET_64BIT \ + ? (((BYTES) + 7) & (-8)) \ + : (((BYTES) + 1) & (-2))) -#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & (-2)) +/* If defined, the maximum amount of space required for outgoing arguments will + be computed and placed into the variable + `current_function_outgoing_args_size'. No space will be pushed onto the + stack for each call; instead, the function prologue should increase the stack + frame size by this amount. */ + +#define ACCUMULATE_OUTGOING_ARGS TARGET_ACCUMULATE_OUTGOING_ARGS + +/* If defined, a C expression whose value is nonzero when we want to use PUSH + instructions to pass outgoing arguments. */ + +#define PUSH_ARGS (TARGET_PUSH_ARGS && !ACCUMULATE_OUTGOING_ARGS) /* Offset of first parameter from the argument pointer register value. */ #define FIRST_PARM_OFFSET(FNDECL) 0 +/* Define this macro if functions should assume that stack space has been + allocated for arguments even when their values are passed in registers. + + The value of this macro is the size, in bytes, of the area reserved for + arguments passed in registers for the function represented by FNDECL. + + This space can be allocated by the caller, or be a part of the + machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says + which. */ +#define REG_PARM_STACK_SPACE(FNDECL) 0 + +/* Define as a C expression that evaluates to nonzero if we do not know how + to pass TYPE solely in registers. The file expr.h defines a + definition that is usually appropriate, refer to expr.h for additional + documentation. If `REG_PARM_STACK_SPACE' is defined, the argument will be + computed in the stack and then loaded into a register. */ +#define MUST_PASS_IN_STACK(MODE, TYPE) \ + ((TYPE) != 0 \ + && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ + || TREE_ADDRESSABLE (TYPE) \ + || ((MODE) == TImode) \ + || ((MODE) == BLKmode \ + && ! ((TYPE) != 0 \ + && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ + && 0 == (int_size_in_bytes (TYPE) \ + % (PARM_BOUNDARY / BITS_PER_UNIT))) \ + && (FUNCTION_ARG_PADDING (MODE, TYPE) \ + == (BYTES_BIG_ENDIAN ? upward : downward))))) + /* 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), @@ -1059,22 +1638,24 @@ enum reg_class 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 RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \ + ix86_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))) + ix86_function_value (VALTYPE) + +#define FUNCTION_VALUE_REGNO_P(N) \ + ix86_function_value_regno_p (N) /* 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)) + ix86_libcall_value (MODE) /* Define the size of the result block used for communication between untyped_call and untyped_return. The block contains a DImode value @@ -1083,7 +1664,7 @@ enum reg_class #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 FUNCTION_ARG_REGNO_P(N) ix86_function_arg_regno_p (N) /* Define a data type for recording info about an argument list during the scan of that argument list. This data type should @@ -1091,25 +1672,29 @@ enum reg_class 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 { +typedef struct ix86_args { int words; /* # words passed so far */ int nregs; /* # registers available for passing */ int regno; /* next available register number */ + int sse_words; /* # sse words passed so far */ + int sse_nregs; /* # sse registers available for passing */ + int sse_regno; /* next available sse register number */ + int maybe_vaarg; /* true for calls to possibly vardic fncts. */ } 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)) +#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 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, @@ -1125,404 +1710,79 @@ typedef struct i386_args { (otherwise it is an extra parameter matching an ellipsis). */ #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - (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. */ +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 -#undef ASM_OUTPUT_FUNCTION_PREFIX -#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \ - asm_output_function_prefix (FILE, FNNAME) +/* If PIC, we cannot make sibling calls to global functions + because the PLT requires %ebx live. + If we are returning floats on the register stack, we cannot make + sibling calls to functions that return floats. (The stack adjust + instruction will wind up after the sibcall jump, and not be executed.) */ +#define FUNCTION_OK_FOR_SIBCALL(DECL) \ + ((DECL) \ + && (! flag_pic || ! TREE_PUBLIC (DECL)) \ + && (! TARGET_FLOAT_RETURNS_IN_80387 \ + || ! FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (DECL)))) \ + || FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (cfun->decl)))))) -/* 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. */ +/* Perform any needed actions needed for a function that is receiving a + variable number of arguments. -#define FUNCTION_PROLOGUE(FILE, SIZE) \ - function_prologue (FILE, SIZE) + CUM is as above. -/* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. */ + MODE and TYPE are the mode and type of the current parameter. -#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"); \ - } \ -} + PRETEND_SIZE is a variable that should be set to the amount of stack + that must be pushed by the prolog to pretend that our caller pushed + it. + Normally, this macro will push all remaining incoming registers on the + stack and set PRETEND_SIZE to the length of the registers pushed. */ -/* 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. +#define SETUP_INCOMING_VARARGS(CUM, MODE, TYPE, PRETEND_SIZE, NO_RTL) \ + ix86_setup_incoming_varargs (&(CUM), (MODE), (TYPE), &(PRETEND_SIZE), \ + (NO_RTL)) - profile_block_flag == 0, no option used: +/* Define the `__builtin_va_list' type for the ABI. */ +#define BUILD_VA_LIST_TYPE(VALIST) \ + ((VALIST) = ix86_build_va_list ()) - No profiling done. +/* Implement `va_start' for varargs and stdarg. */ +#define EXPAND_BUILTIN_VA_START(STDARG, VALIST, NEXTARG) \ + ix86_va_start ((STDARG), (VALIST), (NEXTARG)) - profile_block_flag == 1, -a option used. +/* Implement `va_arg'. */ +#define EXPAND_BUILTIN_VA_ARG(VALIST, TYPE) \ + ix86_va_arg ((VALIST), (TYPE)) - Count frequency of execution of every basic block. +/* This macro is invoked at the end of compilation. It is used here to + output code for -fpic that will load the return address into %ebx. */ - profile_block_flag == 2, -ax option used. +#undef ASM_FILE_END +#define ASM_FILE_END(FILE) ix86_asm_file_end (FILE) - 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: - -*/ +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ -#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; \ - \ +#define FUNCTION_PROFILER(FILE, LABELNO) \ +do { \ + if (flag_pic) \ + { \ + fprintf ((FILE), "\tleal\t%sP%d@GOTOFF(%%ebx),%%edx\n", \ + LPREFIX, (LABELNO)); \ + fprintf ((FILE), "\tcall\t*_mcount@GOT(%%ebx)\n"); \ } \ - } \ -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; \ - \ + else \ + { \ + fprintf ((FILE), "\tmovl\t$%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ + fprintf ((FILE), "\tcall\t_mcount\n"); \ } \ - } \ -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"); +} while (0) /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in @@ -1534,35 +1794,6 @@ while (0) #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. */ @@ -1575,23 +1806,14 @@ do { \ /* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 10 +#define TRAMPOLINE_SIZE (TARGET_64BIT ? 23 : 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); \ -} +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ + x86_initialize_trampoline ((TRAMP), (FNADDR), (CXT)) /* Definitions for register eliminations. @@ -1600,57 +1822,31 @@ do { \ 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}} + There are two registers that can always be eliminated on the i386. + The frame pointer and the arg pointer can be replaced by either the + hard frame pointer or to the stack pointer, depending upon the + circumstances. The hard frame pointer is not used before reload and + so it is not eligible for elimination. */ -/* Given FROM and TO register numbers, say whether this elimination is allowed. - Frame pointer elimination is automatically handled. +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \ - For the i386, if frame pointer elimination is being done, we would like to - convert ap into sp, not fp. +/* Given FROM and TO register numbers, say whether this elimination is + allowed. Frame pointer elimination is automatically handled. All other eliminations are valid. */ -#define CAN_ELIMINATE(FROM, TO) \ - ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \ - ? ! frame_pointer_needed \ - : 1) +#define CAN_ELIMINATE(FROM, TO) \ + ((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; \ - } \ -} +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + ((OFFSET) = ix86_initial_elimination_offset ((FROM), (TO))) /* Addressing modes, and classification of registers for them. */ @@ -1668,17 +1864,28 @@ do { \ 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) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + ((REGNO) < STACK_POINTER_REGNUM \ + || (REGNO >= FIRST_REX_INT_REG \ + && (REGNO) <= LAST_REX_INT_REG) \ + || ((unsigned) reg_renumber[(REGNO)] >= FIRST_REX_INT_REG \ + && (unsigned) reg_renumber[(REGNO)] <= LAST_REX_INT_REG) \ + || (unsigned) reg_renumber[(REGNO)] < STACK_POINTER_REGNUM) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) <= STACK_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO >= FIRST_REX_INT_REG \ + && (REGNO) <= LAST_REX_INT_REG) \ + || ((unsigned) reg_renumber[(REGNO)] >= FIRST_REX_INT_REG \ + && (unsigned) reg_renumber[(REGNO)] <= LAST_REX_INT_REG) \ + || (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. @@ -1697,31 +1904,29 @@ do { \ /* Non strict versions, pseudos are ok */ #define REG_OK_FOR_INDEX_NONSTRICT_P(X) \ (REGNO (X) < STACK_POINTER_REGNUM \ + || (REGNO (X) >= FIRST_REX_INT_REG \ + && REGNO (X) <= LAST_REX_INT_REG) \ || 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) == FRAME_POINTER_REGNUM \ + || (REGNO (X) >= FIRST_REX_INT_REG \ + && REGNO (X) <= LAST_REX_INT_REG) \ || 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) +#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) #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) +#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) #endif /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression @@ -1739,30 +1944,41 @@ do { \ #define CONSTANT_ADDRESS_P(X) \ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \ - || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST) + || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \ + || GET_CODE (X) == CONST_DOUBLE) /* 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) +#define LEGITIMATE_CONSTANT_P(X) 1 #ifdef REG_OK_STRICT #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ -{ \ - if (legitimate_address_p (MODE, X, 1)) \ +do { \ + if (legitimate_address_p ((MODE), (X), 1)) \ goto ADDR; \ -} +} while (0) #else #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ -{ \ - if (legitimate_address_p (MODE, X, 0)) \ +do { \ + if (legitimate_address_p ((MODE), (X), 0)) \ goto ADDR; \ -} +} while (0) #endif +/* If defined, a C expression to determine the base term of address X. + This macro is used in only one place: `find_base_term' in alias.c. + + It is always safe for this macro to not be defined. It exists so + that alias analysis can understand machine-dependent addresses. + + The typical use of this macro is to handle addresses containing + a label_ref or symbol_ref within an UNSPEC. */ + +#define FIND_BASE_TERM(X) ix86_find_base_term (X) + /* 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. @@ -1785,32 +2001,256 @@ do { \ 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)) \ +do { \ + (X) = legitimize_address ((X), (OLDX), (MODE)); \ + if (memory_address_p ((MODE), (X))) \ goto WIN; \ -} +} while (0) -#define REWRITE_ADDRESS(x) rewrite_address(x) +#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 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))) + (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 GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ +do { \ + if (GET_CODE (ADDR) == POST_INC \ + || GET_CODE (ADDR) == POST_DEC) \ + goto LABEL; \ +} while (0) + +/* Codes for all the SSE/MMX builtins. */ +enum ix86_builtins +{ + IX86_BUILTIN_ADDPS, + IX86_BUILTIN_ADDSS, + IX86_BUILTIN_DIVPS, + IX86_BUILTIN_DIVSS, + IX86_BUILTIN_MULPS, + IX86_BUILTIN_MULSS, + IX86_BUILTIN_SUBPS, + IX86_BUILTIN_SUBSS, + + IX86_BUILTIN_CMPEQPS, + IX86_BUILTIN_CMPLTPS, + IX86_BUILTIN_CMPLEPS, + IX86_BUILTIN_CMPGTPS, + IX86_BUILTIN_CMPGEPS, + IX86_BUILTIN_CMPNEQPS, + IX86_BUILTIN_CMPNLTPS, + IX86_BUILTIN_CMPNLEPS, + IX86_BUILTIN_CMPNGTPS, + IX86_BUILTIN_CMPNGEPS, + IX86_BUILTIN_CMPORDPS, + IX86_BUILTIN_CMPUNORDPS, + IX86_BUILTIN_CMPNEPS, + IX86_BUILTIN_CMPEQSS, + IX86_BUILTIN_CMPLTSS, + IX86_BUILTIN_CMPLESS, + IX86_BUILTIN_CMPGTSS, + IX86_BUILTIN_CMPGESS, + IX86_BUILTIN_CMPNEQSS, + IX86_BUILTIN_CMPNLTSS, + IX86_BUILTIN_CMPNLESS, + IX86_BUILTIN_CMPNGTSS, + IX86_BUILTIN_CMPNGESS, + IX86_BUILTIN_CMPORDSS, + IX86_BUILTIN_CMPUNORDSS, + IX86_BUILTIN_CMPNESS, + + IX86_BUILTIN_COMIEQSS, + IX86_BUILTIN_COMILTSS, + IX86_BUILTIN_COMILESS, + IX86_BUILTIN_COMIGTSS, + IX86_BUILTIN_COMIGESS, + IX86_BUILTIN_COMINEQSS, + IX86_BUILTIN_UCOMIEQSS, + IX86_BUILTIN_UCOMILTSS, + IX86_BUILTIN_UCOMILESS, + IX86_BUILTIN_UCOMIGTSS, + IX86_BUILTIN_UCOMIGESS, + IX86_BUILTIN_UCOMINEQSS, + + IX86_BUILTIN_CVTPI2PS, + IX86_BUILTIN_CVTPS2PI, + IX86_BUILTIN_CVTSI2SS, + IX86_BUILTIN_CVTSS2SI, + IX86_BUILTIN_CVTTPS2PI, + IX86_BUILTIN_CVTTSS2SI, + + IX86_BUILTIN_MAXPS, + IX86_BUILTIN_MAXSS, + IX86_BUILTIN_MINPS, + IX86_BUILTIN_MINSS, + + IX86_BUILTIN_LOADAPS, + IX86_BUILTIN_LOADUPS, + IX86_BUILTIN_STOREAPS, + IX86_BUILTIN_STOREUPS, + IX86_BUILTIN_LOADSS, + IX86_BUILTIN_STORESS, + IX86_BUILTIN_MOVSS, + + IX86_BUILTIN_MOVHLPS, + IX86_BUILTIN_MOVLHPS, + IX86_BUILTIN_LOADHPS, + IX86_BUILTIN_LOADLPS, + IX86_BUILTIN_STOREHPS, + IX86_BUILTIN_STORELPS, + + IX86_BUILTIN_MASKMOVQ, + IX86_BUILTIN_MOVMSKPS, + IX86_BUILTIN_PMOVMSKB, + + IX86_BUILTIN_MOVNTPS, + IX86_BUILTIN_MOVNTQ, + + IX86_BUILTIN_PACKSSWB, + IX86_BUILTIN_PACKSSDW, + IX86_BUILTIN_PACKUSWB, + + IX86_BUILTIN_PADDB, + IX86_BUILTIN_PADDW, + IX86_BUILTIN_PADDD, + IX86_BUILTIN_PADDSB, + IX86_BUILTIN_PADDSW, + IX86_BUILTIN_PADDUSB, + IX86_BUILTIN_PADDUSW, + IX86_BUILTIN_PSUBB, + IX86_BUILTIN_PSUBW, + IX86_BUILTIN_PSUBD, + IX86_BUILTIN_PSUBSB, + IX86_BUILTIN_PSUBSW, + IX86_BUILTIN_PSUBUSB, + IX86_BUILTIN_PSUBUSW, + + IX86_BUILTIN_PAND, + IX86_BUILTIN_PANDN, + IX86_BUILTIN_POR, + IX86_BUILTIN_PXOR, + + IX86_BUILTIN_PAVGB, + IX86_BUILTIN_PAVGW, + + IX86_BUILTIN_PCMPEQB, + IX86_BUILTIN_PCMPEQW, + IX86_BUILTIN_PCMPEQD, + IX86_BUILTIN_PCMPGTB, + IX86_BUILTIN_PCMPGTW, + IX86_BUILTIN_PCMPGTD, + + IX86_BUILTIN_PEXTRW, + IX86_BUILTIN_PINSRW, + + IX86_BUILTIN_PMADDWD, + + IX86_BUILTIN_PMAXSW, + IX86_BUILTIN_PMAXUB, + IX86_BUILTIN_PMINSW, + IX86_BUILTIN_PMINUB, + + IX86_BUILTIN_PMULHUW, + IX86_BUILTIN_PMULHW, + IX86_BUILTIN_PMULLW, + + IX86_BUILTIN_PSADBW, + IX86_BUILTIN_PSHUFW, + + IX86_BUILTIN_PSLLW, + IX86_BUILTIN_PSLLD, + IX86_BUILTIN_PSLLQ, + IX86_BUILTIN_PSRAW, + IX86_BUILTIN_PSRAD, + IX86_BUILTIN_PSRLW, + IX86_BUILTIN_PSRLD, + IX86_BUILTIN_PSRLQ, + IX86_BUILTIN_PSLLWI, + IX86_BUILTIN_PSLLDI, + IX86_BUILTIN_PSLLQI, + IX86_BUILTIN_PSRAWI, + IX86_BUILTIN_PSRADI, + IX86_BUILTIN_PSRLWI, + IX86_BUILTIN_PSRLDI, + IX86_BUILTIN_PSRLQI, + + IX86_BUILTIN_PUNPCKHBW, + IX86_BUILTIN_PUNPCKHWD, + IX86_BUILTIN_PUNPCKHDQ, + IX86_BUILTIN_PUNPCKLBW, + IX86_BUILTIN_PUNPCKLWD, + IX86_BUILTIN_PUNPCKLDQ, + + IX86_BUILTIN_SHUFPS, + + IX86_BUILTIN_RCPPS, + IX86_BUILTIN_RCPSS, + IX86_BUILTIN_RSQRTPS, + IX86_BUILTIN_RSQRTSS, + IX86_BUILTIN_SQRTPS, + IX86_BUILTIN_SQRTSS, + + IX86_BUILTIN_UNPCKHPS, + IX86_BUILTIN_UNPCKLPS, + + IX86_BUILTIN_ANDPS, + IX86_BUILTIN_ANDNPS, + IX86_BUILTIN_ORPS, + IX86_BUILTIN_XORPS, + + IX86_BUILTIN_EMMS, + IX86_BUILTIN_LDMXCSR, + IX86_BUILTIN_STMXCSR, + IX86_BUILTIN_SFENCE, + + /* 3DNow! Original */ + IX86_BUILTIN_FEMMS, + IX86_BUILTIN_PAVGUSB, + IX86_BUILTIN_PF2ID, + IX86_BUILTIN_PFACC, + IX86_BUILTIN_PFADD, + IX86_BUILTIN_PFCMPEQ, + IX86_BUILTIN_PFCMPGE, + IX86_BUILTIN_PFCMPGT, + IX86_BUILTIN_PFMAX, + IX86_BUILTIN_PFMIN, + IX86_BUILTIN_PFMUL, + IX86_BUILTIN_PFRCP, + IX86_BUILTIN_PFRCPIT1, + IX86_BUILTIN_PFRCPIT2, + IX86_BUILTIN_PFRSQIT1, + IX86_BUILTIN_PFRSQRT, + IX86_BUILTIN_PFSUB, + IX86_BUILTIN_PFSUBR, + IX86_BUILTIN_PI2FD, + IX86_BUILTIN_PMULHRW, + + /* 3DNow! Athlon Extensions */ + IX86_BUILTIN_PF2IW, + IX86_BUILTIN_PFNACC, + IX86_BUILTIN_PFPNACC, + IX86_BUILTIN_PI2FW, + IX86_BUILTIN_PSWAPDSI, + IX86_BUILTIN_PSWAPDSF, + + IX86_BUILTIN_SSE_ZERO, + IX86_BUILTIN_MMX_ZERO, + + IX86_BUILTIN_MAX +}; /* Define this macro if references to a symbol must be treated differently depending on something about the variable or @@ -1819,35 +2259,29 @@ do { \ 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 () +#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 (GET_CODE (rtl) == MEM) \ + { \ + 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) /* The `FINALIZE_PIC' macro serves as a hook to emit these special codes once the function is being compiled into assembly code, but @@ -1856,93 +2290,61 @@ while (0) 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) +#define FINALIZE_PIC \ + (current_function_uses_pic_offset_table |= current_function_profile) -/* 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 +#define REGPARM_MAX (TARGET_64BIT ? 6 : 3) + +#define SSE_REGPARM_MAX (TARGET_64BIT ? 8 : 0) /* Specify the machine mode that this machine uses for the index in the tablejump instruction. */ -#define CASE_VECTOR_MODE Pmode +#define CASE_VECTOR_MODE (!TARGET_64BIT || flag_pic ? SImode : DImode) /* 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. */ + 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 +/* Number of bytes moved into a data cache for a single prefetch operation. */ +#define PREFETCH_BLOCK ix86_cost->prefetch_block + +/* Number of prefetch operations that can be done in parallel. */ +#define SIMULTANEOUS_PREFETCHES ix86_cost->simultaneous_prefetches + /* Max number of bytes we can move from memory to memory in one reasonably fast instruction. */ -#define MOVE_MAX 4 +#define MOVE_MAX 16 + +/* MOVE_MAX_PIECES is the number of bytes at a time which we can + move efficiently, as opposed to MOVE_MAX which is the maximum + number of bytes we can move with a single instruction. */ +#define MOVE_MAX_PIECES (TARGET_64BIT ? 8 : 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. */ + If you don't define this, a reasonable default is used. */ -#define MOVE_RATIO 5 +#define MOVE_RATIO (optimize_size ? 3 : ix86_cost->move_ratio) /* 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. */ +/* On i386, shifts do truncate the count. But bit opcodes don't. */ /* #define SHIFT_COUNT_TRUNCATED */ @@ -1958,12 +2360,27 @@ while (0) /* When a prototype says `char' or `short', really pass an `int'. (The 386 can't easily push less than an int.) */ -#define PROMOTE_PROTOTYPES +#define PROMOTE_PROTOTYPES 1 + +/* A macro to update M and UNSIGNEDP when an object whose type is + TYPE and which has the specified mode and signedness is to be + stored in a register. This macro is only called when TYPE is a + scalar type. + + On i386 it is sometimes useful to promote HImode and QImode + quantities to SImode. The choice depends on target type. */ + +#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ +do { \ + if (((MODE) == HImode && TARGET_PROMOTE_HI_REGS) \ + || ((MODE) == QImode && TARGET_PROMOTE_QI_REGS)) \ + (MODE) = SImode; \ +} while (0) /* 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 +#define Pmode (TARGET_64BIT ? DImode : SImode) /* A function address in a call instruction is a byte address (for indexing purposes) @@ -1983,28 +2400,32 @@ while (0) CODE is the expression code--redundant, since it can be obtained with `GET_CODE (X)'. */ -#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ +#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; \ + if (TARGET_64BIT && !x86_64_sign_extended_value (RTX)) \ + return 3; \ + if (TARGET_64BIT && !x86_64_zero_extended_value (RTX)) \ + return 2; \ + return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \ \ case CONST_DOUBLE: \ { \ int code; \ if (GET_MODE (RTX) == VOIDmode) \ - return 2; \ + return 0; \ \ code = standard_80387_constant_p (RTX); \ - return code == 1 ? 0 : \ - code == 2 ? 1 : \ - 2; \ + return code == 1 ? 1 : \ + code == 2 ? 2 : \ + 3; \ } /* 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;} +#define TOPLEVEL_COSTS_N_INSNS(N) \ + do { total = COSTS_N_INSNS (N); goto egress_rtx_costs; } while (0) /* Like `CONST_COSTS' but applies to nonconstant RTL expressions. This can be used, for example, to indicate how costly a multiply @@ -2016,20 +2437,33 @@ while (0) 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) \ +#define RTX_COSTS(X, CODE, OUTER_CODE) \ + case ZERO_EXTEND: \ + /* The zero extensions is often completely free on x86_64, so make \ + it as cheap as possible. */ \ + if (TARGET_64BIT && GET_MODE (X) == DImode \ + && GET_MODE (XEXP (X, 0)) == SImode) \ + { \ + total = 1; goto egress_rtx_costs; \ + } \ + else \ + TOPLEVEL_COSTS_N_INSNS (TARGET_ZERO_EXTEND_WITH_AND ? \ + ix86_cost->add : ix86_cost->movzx); \ + break; \ + case SIGN_EXTEND: \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->movsx); \ + break; \ case ASHIFT: \ if (GET_CODE (XEXP (X, 1)) == CONST_INT \ - && GET_MODE (XEXP (X, 0)) == SImode) \ + && (GET_MODE (XEXP (X, 0)) != DImode || TARGET_64BIT)) \ { \ 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); \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \ + if ((value == 2 || value == 3) \ + && !TARGET_DECOMPOSE_LEA \ + && ix86_cost->lea <= ix86_cost->shift_const) \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->lea); \ } \ /* fall through */ \ \ @@ -2037,23 +2471,31 @@ while (0) case ASHIFTRT: \ case LSHIFTRT: \ case ROTATERT: \ - if (GET_MODE (XEXP (X, 0)) == DImode) \ + if (!TARGET_64BIT && 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); \ + TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const + 2); \ + else \ + TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_const * 2); \ + } \ + else \ + { \ + if (GET_CODE (XEXP (X, 1)) == AND) \ + TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 2); \ + else \ + TOPLEVEL_COSTS_N_INSNS(ix86_cost->shift_var * 6 + 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); \ + else \ + { \ + if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_const); \ + else \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->shift_var); \ + } \ + break; \ \ case MULT: \ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ @@ -2061,28 +2503,15 @@ while (0) 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); \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \ + + nbits * ix86_cost->mult_bit); \ } \ - \ else /* This is arbitrary */ \ TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \ + 7 * ix86_cost->mult_bit); \ @@ -2094,27 +2523,68 @@ while (0) 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); \ + if (!TARGET_DECOMPOSE_LEA \ + && INTEGRAL_MODE_P (GET_MODE (X)) \ + && GET_MODE_BITSIZE (GET_MODE (X)) <= GET_MODE_BITSIZE (Pmode)) \ + { \ + if (GET_CODE (XEXP (X, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (X, 0), 0)) == MULT \ + && GET_CODE (XEXP (XEXP (XEXP (X, 0), 0), 1)) == CONST_INT \ + && CONSTANT_P (XEXP (X, 1))) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (X, 0), 0), 1));\ + if (val == 2 || val == 4 || val == 8) \ + { \ + return (COSTS_N_INSNS (ix86_cost->lea) \ + + rtx_cost (XEXP (XEXP (X, 0), 1), \ + (OUTER_CODE)) \ + + rtx_cost (XEXP (XEXP (XEXP (X, 0), 0), 0), \ + (OUTER_CODE)) \ + + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \ + } \ + } \ + else if (GET_CODE (XEXP (X, 0)) == MULT \ + && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT) \ + { \ + HOST_WIDE_INT val = INTVAL (XEXP (XEXP (X, 0), 1)); \ + if (val == 2 || val == 4 || val == 8) \ + { \ + return (COSTS_N_INSNS (ix86_cost->lea) \ + + rtx_cost (XEXP (XEXP (X, 0), 0), \ + (OUTER_CODE)) \ + + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \ + } \ + } \ + else if (GET_CODE (XEXP (X, 0)) == PLUS) \ + { \ + return (COSTS_N_INSNS (ix86_cost->lea) \ + + rtx_cost (XEXP (XEXP (X, 0), 0), (OUTER_CODE)) \ + + rtx_cost (XEXP (XEXP (X, 0), 1), (OUTER_CODE)) \ + + rtx_cost (XEXP (X, 1), (OUTER_CODE))); \ + } \ + } \ \ /* 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)); \ + if (!TARGET_64BIT && 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))); \ + \ + /* fall through */ \ case NEG: \ case NOT: \ - if (GET_MODE (X) == DImode) \ - TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \ - TOPLEVEL_COSTS_N_INSNS (ix86_cost->add) + if (!TARGET_64BIT && GET_MODE (X) == DImode) \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2); \ + TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \ + \ + egress_rtx_costs: \ + break; /* An expression giving the cost of an addressing mode that contains @@ -2164,28 +2634,19 @@ while (0) 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) + ix86_address_cost (RTX) -/* 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'. +/* A C expression for the cost of moving data from a register in class FROM to + one in class TO. The classes are expressed using the enumeration values + such as `GENERAL_REGS'. A value of 2 is the default; other values are + interpreted relative to that. - 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) + It is not required that the cost always equal 2 when FROM is the same as TO; + on some machines it is expensive to move between registers if they are not + general registers. */ +#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ + ix86_register_move_cost ((MODE), (CLASS1), (CLASS2)) /* 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 @@ -2195,12 +2656,13 @@ while (0) between two registers, you should define this macro to express the relative cost. */ -/* #define MEMORY_MOVE_COST(M,C,I) 2 */ +#define MEMORY_MOVE_COST(MODE, CLASS, IN) \ + ix86_memory_move_cost ((MODE), (CLASS), (IN)) /* 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 BRANCH_COST ix86_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 @@ -2221,19 +2683,6 @@ while (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. @@ -2246,7 +2695,7 @@ while (0) If the value of this macro is always zero, it need not be defined. */ -/* #define SLOW_UNALIGNED_ACCESS 0 */ +/* #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) 0 */ /* Define this macro to inhibit strength reduction of memory addresses. (On some machines, such strength reduction seems to do @@ -2267,111 +2716,63 @@ while (0) 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. */ + For the i386, we need separate modes when floating-point + equality comparisons are being done. + + Add CCNO to indicate comparisons against zero that requires + Overflow flag to be unset. Sign bit test is used instead and + thus can be used to form "a&b>0" type of tests. -#define EXTRA_CC_MODES CCFPEQmode + Add CCGC to indicate comparisons agains zero that allows + unspecified garbage in the Carry flag. This mode is used + by inc/dec instructions. -/* Define the names for the modes specified above. */ -#define EXTRA_CC_NAMES "CCFPEQ" + Add CCGOC to indicate comparisons agains zero that allows + unspecified garbage in the Carry and Overflow flag. This + mode is used to simulate comparisons of (a-b) and (a+b) + against zero using sub/cmp/add operations. + + Add CCZ to indicate that only the Zero flag is valid. */ + +#define EXTRA_CC_MODES \ + CC (CCGCmode, "CCGC") \ + CC (CCGOCmode, "CCGOC") \ + CC (CCNOmode, "CCNO") \ + CC (CCZmode, "CCZ") \ + CC (CCFPmode, "CCFP") \ + CC (CCFPUmode, "CCFPU") /* 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 + VOIDmode should be used in all other cases. -/* 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 + For integer comparisons against zero, reduce to CCNOmode or CCZmode if + possible, to allow for more combinations. */ -/* 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 +#define SELECT_CC_MODE(OP, X, Y) ix86_cc_mode ((OP), (X), (Y)) -/* 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. */ +/* Return non-zero if MODE implies a floating point inequality can be + reversed. */ -#define NOTICE_UPDATE_CC(EXP, INSN) \ - notice_update_cc((EXP)) +#define REVERSIBLE_CC_MODE(MODE) 1 -/* 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. */ +/* A C expression whose value is reversed condition code of the CODE for + comparison done in CC_MODE mode. */ +#define REVERSE_CONDITION(CODE, MODE) \ + ((MODE) != CCFPmode && (MODE) != CCFPUmode ? reverse_condition (CODE) \ + : reverse_condition_maybe_unordered (CODE)) -#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). */ + 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. @@ -2379,9 +2780,15 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); 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)","" } +#undef HI_REGISTER_NAMES +#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)","", \ + "flags","fpsr", "dirflag", "frame", \ + "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7", \ + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" , \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \ + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"} #define REGISTER_NAMES HI_REGISTER_NAMES @@ -2390,87 +2797,75 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)(); #define ADDITIONAL_REGISTER_NAMES \ { { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, \ { "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, \ + { "rax", 0 }, { "rdx", 1 }, { "rcx", 2 }, { "rbx", 3 }, \ + { "rsi", 4 }, { "rdi", 5 }, { "rbp", 6 }, { "rsp", 7 }, \ { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \ - { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } } + { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 }, \ + { "mm0", 8}, { "mm1", 9}, { "mm2", 10}, { "mm3", 11}, \ + { "mm4", 12}, { "mm5", 13}, { "mm6", 14}, { "mm7", 15} } /* 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",} +{"al", "dl", "cl", "bl", "sil", "dil", "bpl", "spl",} /* These parallel the array above, and can be used to access bits 8:15 - of regs 0 through 3. */ + 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) +#define DBX_REGISTER_NUMBER(N) \ + (TARGET_64BIT ? dbx64_register_map[(N)] : dbx_register_map[(N)]) + +extern int const dbx_register_map[FIRST_PSEUDO_REGISTER]; +extern int const dbx64_register_map[FIRST_PSEUDO_REGISTER]; +extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER]; /* 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)))) +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, -UNITS_PER_WORD)) \ + : gen_rtx_MEM (Pmode, plus_constant (FRAME, UNITS_PER_WORD))) -/* PC is dbx register 8; let's use that column for RA. */ -#define DWARF_FRAME_RETURN_COLUMN 8 +/* PC is dbx register 8; let's use that column for RA. */ +#define DWARF_FRAME_RETURN_COLUMN (TARGET_64BIT ? 16 : 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 INCOMING_FRAME_SP_OFFSET UNITS_PER_WORD -#define ASM_OUTPUT_LABEL(FILE,NAME) \ - (assemble_name (FILE, NAME), fputs (":\n", FILE)) +/* Describe how we implement __builtin_eh_return. */ +#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) : INVALID_REGNUM) +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 2) -/* 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) +/* Select a format to encode pointers in exception handling data. CODE + is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is + true if the symbol may be affected by dynamic relocations. -/* This is how to output a `long double' extended real constant. */ + ??? All x86 object file formats are capable of representing this. + After all, the relocation needed is the same as for the call insn. + Whether or not a particular assembler allows us to enter such, I + guess we'll have to see. */ +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ + (flag_pic \ + ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\ + : DW_EH_PE_absptr) -#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. */ +/* 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_FLOAT(FILE,VALUE) \ -do { long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \ - } while (0) +#define ASM_OUTPUT_LABEL(FILE, NAME) \ + (assemble_name ((FILE), (NAME)), fputs (":\n", (FILE))) /* Store in OUTPUT a string (made with alloca) containing an assembler-name for a local static variable named NAME. @@ -2480,327 +2875,339 @@ do { long l; \ ( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ +#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \ + asm_fprintf ((FILE), "\tpush{l}\t%%e%s\n", reg_names[(REGNO)]) -/* 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?? */ +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ -#define ASM_OUTPUT_SHORT(FILE,VALUE) \ -( fprintf (FILE, "%s ", ASM_SHORT), \ - output_addr_const (FILE,(VALUE)), \ - putc('\n',FILE)) +#define ASM_OUTPUT_REG_POP(FILE, REGNO) \ + asm_fprintf ((FILE), "\tpop{l}\t%%e%s\n", reg_names[(REGNO)]) -/* -#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)) -*/ +/* This is how to output an element of a case-vector that is absolute. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + ix86_output_addr_vec_elt ((FILE), (VALUE)) -#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 element of a case-vector that is relative. */ -/* This is how to output an assembler line for a numeric constant byte. */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + ix86_output_addr_diff_elt ((FILE), (VALUE), (REL)) -#define ASM_OUTPUT_BYTE(FILE,VALUE) \ - fprintf ((FILE), "%s 0x%x\n", ASM_BYTE_OP, (VALUE)) +/* Under some conditions we need jump tables in the text section, because + the assembler cannot handle label differences between sections. */ -/* This is how to output an insn to push a register on the stack. - It need not be very fast code. */ +#define JUMP_TABLES_IN_TEXT_SECTION \ + (!TARGET_64BIT && flag_pic && !HAVE_AS_GOTOFF_IN_DATA) -#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ - fprintf (FILE, "\tpushl %%e%s\n", reg_names[REGNO]) +/* A C statement that outputs an address constant appropriate to + for DWARF debugging. */ -/* This is how to output an insn to pop a register from the stack. - It need not be very fast code. */ +#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE, X) \ + i386_dwarf_output_addr_const ((FILE), (X)) -#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ - fprintf (FILE, "\tpopl %%e%s\n", reg_names[REGNO]) +/* Either simplify a location expression, or return the original. */ -/* This is how to output an element of a case-vector that is absolute. - */ +#define ASM_SIMPLIFY_DWARF_ADDR(X) \ + i386_simplify_dwarf_addr (X) -#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 +/* Switch to init or fini section via SECTION_OP, emit a call to FUNC, + and switch back. For x86 we do this only to save a few bytes that + would otherwise be unused in the text section. */ +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ + asm (SECTION_OP "\n\t" \ + "call " USER_LABEL_PREFIX #FUNC "\n" \ + TEXT_SECTION_ASM_OP); /* 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) == '_') + Effect of various CODE letters is described in i386.c near + print_operand function. */ + +#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 'q', pretend the mode is DImode. 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) + If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op. */ + +#define PRINT_REG(X, CODE, FILE) \ + print_reg ((X), (CODE), (FILE)) #define PRINT_OPERAND(FILE, X, CODE) \ - print_operand (FILE, X, CODE) + print_operand ((FILE), (X), (CODE)) #define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ - 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); \ +#define DEBUG_PRINT_REG(X, CODE, FILE) \ + do { static const char * const hi_name[] = HI_REGISTER_NAMES; \ + static const char * const qi_name[] = QI_REGISTER_NAMES; \ + fprintf ((FILE), "%d ", REGNO (X)); \ + if (REGNO (X) == FLAGS_REG) \ + { fputs ("flags", (FILE)); break; } \ + if (REGNO (X) == DIRFLAG_REG) \ + { fputs ("dirflag", (FILE)); break; } \ + if (REGNO (X) == FPSR_REG) \ + { fputs ("fpsr", (FILE)); break; } \ if (REGNO (X) == ARG_POINTER_REGNUM) \ - { fputs ("argp", FILE); break; } \ + { fputs ("argp", (FILE)); break; } \ + if (REGNO (X) == FRAME_POINTER_REGNUM) \ + { fputs ("frame", (FILE)); break; } \ if (STACK_TOP_P (X)) \ - { fputs ("st(0)", FILE); break; } \ + { fputs ("st(0)", (FILE)); break; } \ if (FP_REG_P (X)) \ - { fputs (hi_name[REGNO(X)], FILE); break; } \ + { fputs (hi_name[REGNO(X)], (FILE)); break; } \ + if (REX_INT_REG_P (X)) \ + { \ + switch (GET_MODE_SIZE (GET_MODE (X))) \ + { \ + default: \ + case 8: \ + fprintf ((FILE), "r%i", REGNO (X) \ + - FIRST_REX_INT_REG + 8); \ + break; \ + case 4: \ + fprintf ((FILE), "r%id", REGNO (X) \ + - FIRST_REX_INT_REG + 8); \ + break; \ + case 2: \ + fprintf ((FILE), "r%iw", REGNO (X) \ + - FIRST_REX_INT_REG + 8); \ + break; \ + case 1: \ + fprintf ((FILE), "r%ib", REGNO (X) \ + - FIRST_REX_INT_REG + 8); \ + break; \ + } \ + break; \ + } \ switch (GET_MODE_SIZE (GET_MODE (X))) \ { \ + case 8: \ + fputs ("r", (FILE)); \ + fputs (hi_name[REGNO (X)], (FILE)); \ + break; \ default: \ - fputs ("e", FILE); \ + fputs ("e", (FILE)); \ case 2: \ - fputs (hi_name[REGNO (X)], FILE); \ + fputs (hi_name[REGNO (X)], (FILE)); \ break; \ case 1: \ - fputs (qi_name[REGNO (X)], FILE); \ + 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)) +#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 the codes that are matched by predicates in i386.c. */ + +#define PREDICATE_CODES \ + {"x86_64_immediate_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_nonmemory_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_movabs_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_szext_nonmemory_operand", {CONST_INT, SUBREG, REG, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_general_operand", {CONST_INT, SUBREG, REG, MEM, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_szext_general_operand", {CONST_INT, SUBREG, REG, MEM, \ + SYMBOL_REF, LABEL_REF, CONST}}, \ + {"x86_64_zext_immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, \ + SYMBOL_REF, LABEL_REF}}, \ + {"shiftdi_operand", {SUBREG, REG, MEM}}, \ + {"const_int_1_operand", {CONST_INT}}, \ + {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \ + {"aligned_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM}}, \ + {"pic_symbolic_operand", {CONST}}, \ + {"call_insn_operand", {REG, SUBREG, MEM, SYMBOL_REF}}, \ + {"constant_call_address_operand", {SYMBOL_REF, CONST}}, \ + {"const0_operand", {CONST_INT, CONST_DOUBLE}}, \ + {"const1_operand", {CONST_INT}}, \ + {"const248_operand", {CONST_INT}}, \ + {"incdec_operand", {CONST_INT}}, \ + {"mmx_reg_operand", {REG}}, \ + {"reg_no_sp_operand", {SUBREG, REG}}, \ + {"general_no_elim_operand", {CONST_INT, CONST_DOUBLE, CONST, \ + SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}}, \ + {"nonmemory_no_elim_operand", {CONST_INT, REG, SUBREG}}, \ + {"q_regs_operand", {SUBREG, REG}}, \ + {"non_q_regs_operand", {SUBREG, REG}}, \ + {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU, UNORDERED, \ + ORDERED, LT, UNLT, GT, UNGT, LE, UNLE, \ + GE, UNGE, LTGT, UNEQ}}, \ + {"sse_comparison_operator", {EQ, LT, LE, UNORDERED, NE, UNGE, UNGT, \ + ORDERED, UNEQ, UNLT, UNLE, LTGT, GE, GT \ + }}, \ + {"ix86_comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, \ + GTU, UNORDERED, ORDERED, UNLE, UNLT, \ + UNGE, UNGT, LTGT, UNEQ }}, \ + {"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}}, \ + {"ext_register_operand", {SUBREG, REG}}, \ + {"binary_fp_operator", {PLUS, MINUS, MULT, DIV}}, \ + {"mult_operator", {MULT}}, \ + {"div_operator", {DIV}}, \ + {"arith_or_logical_operator", {PLUS, MULT, AND, IOR, XOR, SMIN, SMAX, \ + UMIN, UMAX, COMPARE, MINUS, DIV, MOD, \ + UDIV, UMOD, ASHIFT, ROTATE, ASHIFTRT, \ + LSHIFTRT, ROTATERT}}, \ + {"promotable_binary_operator", {PLUS, MULT, AND, IOR, XOR, ASHIFT}}, \ + {"memory_displacement_operand", {MEM}}, \ + {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ + LABEL_REF, SUBREG, REG, MEM, AND}}, \ + {"long_memory_operand", {MEM}}, + +/* A list of predicates that do special things with modes, and so + should not elicit warnings for VOIDmode match_operand. */ + +#define SPECIAL_MODE_PREDICATES \ + "ext_register_operand", + +/* CM_32 is used by 32bit ABI + CM_SMALL is small model assuming that all code and data fits in the first + 31bits of address space. + CM_KERNEL is model assuming that all code and data fits in the negative + 31bits of address space. + CM_MEDIUM is model assuming that code fits in the first 31bits of address + space. Size of data is unlimited. + CM_LARGE is model making no assumptions about size of particular sections. + + CM_SMALL_PIC is model for PIC libraries assuming that code+data+got/plt + tables first in 31bits of address space. + */ +enum cmodel { + CM_32, + CM_SMALL, + CM_KERNEL, + CM_MEDIUM, + CM_LARGE, + CM_SMALL_PIC +}; -#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \ -do { \ - if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \ - FAIL; \ -} while (0) +/* Size of the RED_ZONE area. */ +#define RED_ZONE_SIZE 128 +/* Reserved area of the red zone for temporaries. */ +#define RED_ZONE_RESERVE 8 +extern const char *ix86_debug_arg_string, *ix86_debug_addr_string; +enum asm_dialect { + ASM_ATT, + ASM_INTEL +}; +extern const char *ix86_asm_string; +extern enum asm_dialect ix86_asm_dialect; +/* Value of -mcmodel specified by user. */ +extern const char *ix86_cmodel_string; +extern enum cmodel ix86_cmodel; -/* 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 (); +extern const char *ix86_cpu_string; /* for -mcpu=<xxx> */ +extern const char *ix86_arch_string; /* for -march=<xxx> */ +extern const char *ix86_fpmath_string; /* for -mfpmath=<xxx> */ +extern const char *ix86_regparm_string; /* # registers to use to pass args */ +extern const char *ix86_align_loops_string; /* power of two alignment for loops */ +extern const char *ix86_align_jumps_string; /* power of two alignment for non-loop jumps */ +extern const char *ix86_align_funcs_string; /* power of two alignment for functions */ +extern const char *ix86_preferred_stack_boundary_string;/* power of two alignment for stack boundary */ +extern const char *ix86_branch_cost_string; /* values 1-5: see jump.c */ +extern int ix86_regparm; /* ix86_regparm_string as a number */ +extern int ix86_preferred_stack_boundary; /* preferred stack boundary alignment in bits */ +extern int ix86_branch_cost; /* values 1-5: see jump.c */ +extern enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER]; /* smalled class containing REGNO */ +extern rtx ix86_compare_op0; /* operand 0 for comparisons */ +extern rtx ix86_compare_op1; /* operand 1 for comparisons */ + +/* To properly truncate FP values into integers, we need to set i387 control + word. We can't emit proper mode switching code before reload, as spills + generated by reload may truncate values incorrectly, but we still can avoid + redundant computation of new control word by the mode switching pass. + The fldcw instructions are still emitted redundantly, but this is probably + not going to be noticeable problem, as most CPUs do have fast path for + the sequence. + + The machinery is to emit simple truncation instructions and split them + before reload to instructions having USEs of two memory locations that + are filled by this code to old and new control word. + + Post-reload pass may be later used to eliminate the redundant fildcw if + needed. */ + +enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY}; + +/* Define this macro if the port needs extra instructions inserted + for mode switching in an optimizing compilation. */ + +#define OPTIMIZE_MODE_SWITCHING(ENTITY) 1 + +/* If you define `OPTIMIZE_MODE_SWITCHING', you have to define this as + initializer for an array of integers. Each initializer element N + refers to an entity that needs mode switching, and specifies the + number of different modes that might need to be set for this + entity. The position of the initializer in the initializer - + starting counting at zero - determines the integer that is used to + refer to the mode-switched entity in question. */ + +#define NUM_MODES_FOR_MODE_SWITCHING { FP_CW_ANY } + +/* ENTITY is an integer specifying a mode-switched entity. If + `OPTIMIZE_MODE_SWITCHING' is defined, you must define this macro to + return an integer value not larger than the corresponding element + in `NUM_MODES_FOR_MODE_SWITCHING', to denote the mode that ENTITY + must be switched into prior to the execution of INSN. */ + +#define MODE_NEEDED(ENTITY, I) \ + (GET_CODE (I) == CALL_INSN \ + || (GET_CODE (I) == INSN && (asm_noperands (PATTERN (I)) >= 0 \ + || GET_CODE (PATTERN (I)) == ASM_INPUT))\ + ? FP_CW_UNINITIALIZED \ + : recog_memoized (I) < 0 || get_attr_type (I) != TYPE_FISTP \ + ? FP_CW_ANY \ + : FP_CW_STORED) + +/* This macro specifies the order in which modes for ENTITY are + processed. 0 is the highest priority. */ + +#define MODE_PRIORITY_TO_MODE(ENTITY, N) (N) + +/* Generate one or more insns to set ENTITY to MODE. HARD_REG_LIVE + is the set of hard registers live at the point where the insn(s) + are to be inserted. */ + +#define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE) \ + ((MODE) == FP_CW_STORED \ + ? emit_i387_cw_initialization (assign_386_stack_local (HImode, 1), \ + assign_386_stack_local (HImode, 2)), 0\ + : 0) + +/* Avoid renaming of stack registers, as doing so in combination with + scheduling just increases amount of live registers at time and in + the turn amount of fxch instructions needed. + + ??? Maybe Pentium chips benefits from renaming, someone can try... */ + +#define HARD_REGNO_RENAME_OK(SRC, TARGET) \ + ((SRC) < FIRST_STACK_REG || (SRC) > LAST_STACK_REG) /* diff --git a/contrib/gcc/config/i386/i386.md b/contrib/gcc/config/i386/i386.md index 649c7d54..b9f6c15 100644 --- a/contrib/gcc/config/i386/i386.md +++ b/contrib/gcc/config/i386/i386.md @@ -1,37 +1,38 @@ -; GCC machine description for Intel X86. -;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000 Free Software -;; Foundation, Inc. +;; GCC machine description for IA-32 and x86-64. +;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +;; Free Software Foundation, Inc. ;; Mostly by William Schelter. - +;; x86_64 support added by Jan Hubicka +;; ;; 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. */ - +;; 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: +;; +;; 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. @@ -41,14 +42,14 @@ ;; '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. @@ -68,1994 +69,3713 @@ ;; 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. +;; 9 This is an `fnstsw' operation. +;; 10 This is a `sahf' operation. +;; 11 This is a `fstcw' operation +;; 12 This is behaviour of add when setting carry flag. +;; 13 This is a `eh_return' placeholder. + +;; For SSE/MMX support: +;; 30 This is `fix', guaranteed to be truncating. +;; 31 This is a `emms' operation. +;; 32 This is a `maskmov' operation. +;; 33 This is a `movmsk' operation. +;; 34 This is a `non-temporal' move. +;; 36 This is used to distinguish COMISS from UCOMISS. +;; 37 This is a `ldmxcsr' operation. +;; 38 This is a forced `movaps' instruction (rather than whatever movti does) +;; 39 This is a forced `movups' instruction (rather than whatever movti does) +;; 40 This is a `stmxcsr' operation. +;; 41 This is a `shuffle' operation. +;; 42 This is a `rcp' operation. +;; 43 This is a `rsqsrt' operation. +;; 44 This is a `sfence' operation. +;; 45 This is a noop to prevent excessive combiner cleverness. +;; 46 This is a `femms' operation. +;; 49 This is a 'pavgusb' operation. +;; 50 This is a `pfrcp' operation. +;; 51 This is a `pfrcpit1' operation. +;; 52 This is a `pfrcpit2' operation. +;; 53 This is a `pfrsqrt' operation. +;; 54 This is a `pfrsqrit1' operation. + +;; Insns whose names begin with "x86_" are emitted by gen_FOO calls +;; from i386.c. + +;; In C guard expressions, put expressions which may be compile-time +;; constants first. This allows for better optimization. For +;; example, write "TARGET_64BIT && reload_completed", not +;; "reload_completed && TARGET_64BIT". + -;; This shadows the processor_type enumeration, so changes must be made -;; to i386.h at the same time. +;; Processor type. This attribute must exactly match the processor_type +;; enumeration in i386.h. +(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon,pentium4" + (const (symbol_ref "ix86_cpu"))) +;; A basic instruction type. Refinements due to arguments to be +;; provided in other attributes. (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") + "other,multi,alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,str,cld,sse,mmx,fistp" + (const_string "other")) + +;; Main data type used by the insn +(define_attr "mode" "unknown,none,QI,HI,SI,DI,unknownfp,SF,DF,XF,TI" + (const_string "unknown")) + +;; Set for i387 operations. +(define_attr "i387" "" + (if_then_else (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp") + (const_int 1) + (const_int 0))) + +;; The (bounding maximum) length of an instruction immediate. +(define_attr "length_immediate" "" + (cond [(eq_attr "type" "incdec,setcc,icmov,ibr,str,cld,lea,other,multi,idiv,sse,mmx") + (const_int 0) + (eq_attr "i387" "1") + (const_int 0) + (eq_attr "type" "alu1,negnot,alu,icmp,imovx,ishift,imul,push,pop") + (symbol_ref "ix86_attr_length_immediate_default(insn,1)") + (eq_attr "type" "imov,test") + (symbol_ref "ix86_attr_length_immediate_default(insn,0)") + (eq_attr "type" "call") + (if_then_else (match_operand 0 "constant_call_address_operand" "") + (const_int 4) + (const_int 0)) + (eq_attr "type" "callv") + (if_then_else (match_operand 1 "constant_call_address_operand" "") + (const_int 4) + (const_int 0)) + (eq_attr "type" "ibr") + (if_then_else (and (ge (minus (match_dup 0) (pc)) + (const_int -128)) + (lt (minus (match_dup 0) (pc)) + (const_int 124))) + (const_int 1) + (const_int 4)) + ] + (symbol_ref "/* Update immediate_length and other attributes! */ abort(),1"))) + +;; The (bounding maximum) length of an instruction address. +(define_attr "length_address" "" + (cond [(eq_attr "type" "str,cld,other,multi,fxch") + (const_int 0) + (and (eq_attr "type" "call") + (match_operand 1 "constant_call_address_operand" "")) + (const_int 0) + (and (eq_attr "type" "callv") + (match_operand 1 "constant_call_address_operand" "")) + (const_int 0) + ] + (symbol_ref "ix86_attr_length_address_default (insn)"))) + +;; Set when length prefix is used. +(define_attr "prefix_data16" "" + (if_then_else (eq_attr "mode" "HI") + (const_int 1) + (const_int 0))) + +;; Set when string REP prefix is used. +(define_attr "prefix_rep" "" (const_int 0)) + +;; Set when 0f opcode prefix is used. +(define_attr "prefix_0f" "" + (if_then_else (eq_attr "type" "imovx,setcc,icmov,sse,mmx") + (const_int 1) + (const_int 0))) + +;; Set when modrm byte is used. +(define_attr "modrm" "" + (cond [(eq_attr "type" "str,cld") + (const_int 0) + (eq_attr "i387" "1") + (const_int 0) + (and (eq_attr "type" "incdec") + (ior (match_operand:SI 1 "register_operand" "") + (match_operand:HI 1 "register_operand" ""))) + (const_int 0) + (and (eq_attr "type" "push") + (not (match_operand 1 "memory_operand" ""))) + (const_int 0) + (and (eq_attr "type" "pop") + (not (match_operand 0 "memory_operand" ""))) + (const_int 0) + (and (eq_attr "type" "imov") + (and (match_operand 0 "register_operand" "") + (match_operand 1 "immediate_operand" ""))) + (const_int 0) + ] + (const_int 1))) + +;; The (bounding maximum) length of an instruction in bytes. +;; ??? fistp is in fact fldcw/fistp/fldcw sequence. Later we may want +;; to split it and compute proper length as for other insns. +(define_attr "length" "" + (cond [(eq_attr "type" "other,multi,fistp") + (const_int 16) + ] + (plus (plus (attr "modrm") + (plus (attr "prefix_0f") + (plus (attr "i387") + (const_int 1)))) + (plus (attr "prefix_rep") + (plus (attr "prefix_data16") + (plus (attr "length_immediate") + (attr "length_address"))))))) + +;; The `memory' attribute is `none' if no memory is referenced, `load' or +;; `store' if there is a simple memory reference therein, or `unknown' +;; if the instruction is complex. + +(define_attr "memory" "none,load,store,both,unknown" + (cond [(eq_attr "type" "other,multi,str") + (const_string "unknown") + (eq_attr "type" "lea,fcmov,fpspc,cld") + (const_string "none") + (eq_attr "type" "fistp") + (const_string "both") + (eq_attr "type" "push") + (if_then_else (match_operand 1 "memory_operand" "") + (const_string "both") + (const_string "store")) + (eq_attr "type" "pop,setcc") + (if_then_else (match_operand 0 "memory_operand" "") + (const_string "both") + (const_string "load")) + (eq_attr "type" "icmp,test") + (if_then_else (ior (match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "")) + (const_string "load") + (const_string "none")) + (eq_attr "type" "ibr") + (if_then_else (match_operand 0 "memory_operand" "") + (const_string "load") + (const_string "none")) + (eq_attr "type" "call") + (if_then_else (match_operand 0 "constant_call_address_operand" "") + (const_string "none") + (const_string "load")) + (eq_attr "type" "callv") + (if_then_else (match_operand 1 "constant_call_address_operand" "") + (const_string "none") + (const_string "load")) + (and (eq_attr "type" "alu1,negnot") + (match_operand 1 "memory_operand" "")) + (const_string "both") + (and (match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "")) + (const_string "both") + (match_operand 0 "memory_operand" "") + (const_string "store") + (match_operand 1 "memory_operand" "") + (const_string "load") + (and (eq_attr "type" "!icmp,test,alu1,negnot,fop1,fsgn,imov,imovx,fmov,fcmp,sse,mmx") + (match_operand 2 "memory_operand" "")) + (const_string "load") + (and (eq_attr "type" "icmov") + (match_operand 3 "memory_operand" "")) + (const_string "load") + ] + (const_string "none"))) - (eq_attr "type" "fld") - (const_string "load") +;; Indicates if an instruction has both an immediate and a displacement. + +(define_attr "imm_disp" "false,true,unknown" + (cond [(eq_attr "type" "other,multi") + (const_string "unknown") + (and (eq_attr "type" "icmp,test,imov") + (and (match_operand 0 "memory_displacement_operand" "") + (match_operand 1 "immediate_operand" ""))) + (const_string "true") + (and (eq_attr "type" "alu,ishift,imul,idiv") + (and (match_operand 0 "memory_displacement_operand" "") + (match_operand 2 "immediate_operand" ""))) + (const_string "true") + ] + (const_string "false"))) + +;; Indicates if an FP operation has an integer source. + +(define_attr "fp_int_src" "false,true" + (const_string "false")) + +;; Describe a user's asm statement. +(define_asm_attributes + [(set_attr "length" "128") + (set_attr "type" "multi")]) + +;; Pentium Scheduling +;; +;; The Pentium is an in-order core with two integer pipelines. + +;; True for insns that behave like prefixed insns on the Pentium. +(define_attr "pent_prefix" "false,true" + (if_then_else (ior (eq_attr "prefix_0f" "1") + (ior (eq_attr "prefix_data16" "1") + (eq_attr "prefix_rep" "1"))) + (const_string "true") + (const_string "false"))) + +;; Categorize how an instruction slots. + +;; The non-MMX Pentium slots an instruction with prefixes on U pipe only, +;; while MMX Pentium can slot it on either U or V. Model non-MMX Pentium +;; rules, because it results in noticeably better code on non-MMX Pentium +;; and doesn't hurt much on MMX. (Prefixed instructions are not very +;; common, so the scheduler usualy has a non-prefixed insn to pair). + +(define_attr "pent_pair" "uv,pu,pv,np" + (cond [(eq_attr "imm_disp" "true") + (const_string "np") + (ior (eq_attr "type" "alu1,alu,imov,icmp,test,lea,incdec") + (and (eq_attr "type" "pop,push") + (eq_attr "memory" "!both"))) + (if_then_else (eq_attr "pent_prefix" "true") + (const_string "pu") + (const_string "uv")) + (eq_attr "type" "ibr") + (const_string "pv") + (and (eq_attr "type" "ishift") + (match_operand 2 "const_int_operand" "")) + (const_string "pu") + (and (eq_attr "type" "call") + (match_operand 0 "constant_call_address_operand" "")) + (const_string "pv") + (and (eq_attr "type" "callv") + (match_operand 1 "constant_call_address_operand" "")) + (const_string "pv") + ] + (const_string "np"))) + +;; Rough readiness numbers. Fine tuning happens in i386.c. +;; +;; u describes pipe U +;; v describes pipe V +;; uv describes either pipe U or V for those that can issue to either +;; np describes not paring +;; fpu describes fpu +;; fpm describes fp insns of different types are not pipelined. +;; +;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real. - (eq_attr "type" "test") - (if_then_else (match_operand 0 "memory_operand" "") - (const_string "load") - (const_string "none")) +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "imul")) + 11 11) - (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")) +(define_function_unit "pent_mul" 1 1 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "imul")) + 11 11) - (and (eq_attr "type" "integer,memory,fpop") - (match_operand 0 "memory_operand" "")) - (const_string "store") +;; Rep movs takes minimally 12 cycles. +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "str")) + 12 12) + +; ??? IDIV for SI takes 46 cycles, for HI 30, for QI 22 +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "idiv")) + 46 46) + +; Fp reg-reg moves takes 1 cycle. Loads takes 1 cycle for SF/DF mode, +; 3 cycles for XFmode. Stores takes 2 cycles for SF/DF and 3 for XF. +; fldz and fld1 takes 2 cycles. Only reg-reg moves are pairable. +; The integer <-> fp conversion is not modeled correctly. Fild behaves +; like normal fp operation and fist takes 6 cycles. + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "fmov") + (and (eq_attr "memory" "load,store") + (eq_attr "mode" "XF")))) + 3 3) + +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "fmov") + (and (eq_attr "memory" "load,store") + (eq_attr "mode" "XF")))) + 3 3) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "fmov") + (ior (match_operand 1 "immediate_operand" "") + (eq_attr "memory" "store")))) + 2 2) - (and (eq_attr "type" "integer,memory,fpop") - (match_operand 1 "memory_operand" "")) - (const_string "load") +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "fmov") + (ior (match_operand 1 "immediate_operand" "") + (eq_attr "memory" "store")))) + 2 2) - (and (eq_attr "type" "binary,imul,fpmul,fpdiv") - (ior (match_operand 1 "memory_operand" "") - (match_operand 2 "memory_operand" ""))) - (const_string "load")] +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "cld")) + 2 2) - (const_string "none"))) +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "fmov") + (eq_attr "memory" "none,load"))) + 1 1) + +; Read/Modify/Write instructions usually take 3 cycles. +(define_function_unit "pent_u" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,alu1,ishift") + (and (eq_attr "pent_pair" "pu") + (eq_attr "memory" "both")))) + 3 3) + +(define_function_unit "pent_uv" 2 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,alu1,ishift") + (and (eq_attr "pent_pair" "!np") + (eq_attr "memory" "both")))) + 3 3) + +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,alu1,negnot,ishift") + (and (eq_attr "pent_pair" "np") + (eq_attr "memory" "both")))) + 3 3) + +; Read/Modify or Modify/Write instructions usually take 2 cycles. +(define_function_unit "pent_u" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,ishift") + (and (eq_attr "pent_pair" "pu") + (eq_attr "memory" "load,store")))) + 2 2) -;; Functional units +(define_function_unit "pent_uv" 2 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,ishift") + (and (eq_attr "pent_pair" "!np") + (eq_attr "memory" "load,store")))) + 2 2) -; (define_function_unit NAME MULTIPLICITY SIMULTANEITY -; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,ishift") + (and (eq_attr "pent_pair" "np") + (eq_attr "memory" "load,store")))) + 2 2) -; 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 +; Insns w/o memory operands and move instructions usually take one cycle. +(define_function_unit "pent_u" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "pent_pair" "pu")) + 1 1) + +(define_function_unit "pent_v" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "pent_pair" "pv")) + 1 1) + +(define_function_unit "pent_uv" 2 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "pent_pair" "!np")) + 1 1) + +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "pent_pair" "np")) + 1 1) + +; Pairable insns only conflict with other non-pairable insns. +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,alu1,ishift") + (and (eq_attr "pent_pair" "!np") + (eq_attr "memory" "both")))) + 3 3 + [(eq_attr "pent_pair" "np")]) + +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (and (eq_attr "type" "alu,alu1,ishift") + (and (eq_attr "pent_pair" "!np") + (eq_attr "memory" "load,store")))) + 2 2 + [(eq_attr "pent_pair" "np")]) + +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "pent_pair" "!np")) + 1 1 + [(eq_attr "pent_pair" "np")]) + +; Floating point instructions usually blocks cycle longer when combined with +; integer instructions, because of the inpaired fxch instruction. +(define_function_unit "pent_np" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp,fistp")) + 2 2 + [(eq_attr "type" "!fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp,fistp")]) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fcmp,fxch,fsgn")) + 1 1) + +; Addition takes 3 cycles; assume other random cruft does as well. +; ??? Trivial fp operations such as fabs or fchs takes only one cycle. +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fop,fop1,fistp")) + 3 1) + +; Multiplication takes 3 cycles and is only half pipelined. +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fmul")) + 3 1) + +(define_function_unit "pent_mul" 1 1 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fmul")) + 2 2) -; pentium has two integer pipelines, the main u pipe and the secondary v pipe. -; and a float pipeline +; ??? This is correct only for fdiv and sqrt -- sin/cos take 65-100 cycles. +; They can overlap with integer insns. Only the last two cycles can overlap +; with other fp insns. Only fsin/fcos can overlap with multiplies. +; Only last two cycles of fsin/fcos can overlap with other instructions. +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fdiv")) + 39 37) + +(define_function_unit "pent_mul" 1 1 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fdiv")) + 39 39) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fpspc")) + 70 68) + +(define_function_unit "pent_mul" 1 1 + (and (eq_attr "cpu" "pentium") + (eq_attr "type" "fpspc")) + 70 70) + +;; Pentium Pro/PII Scheduling +;; +;; The PPro has an out-of-order core, but the instruction decoders are +;; naturally in-order and asymmetric. We get best performance by scheduling +;; for the decoders, for in doing so we give the oo execution unit the +;; most choices. + +;; Categorize how many uops an ia32 instruction evaluates to: +;; one -- an instruction with 1 uop can be decoded by any of the +;; three decoders. +;; few -- an instruction with 1 to 4 uops can be decoded only by +;; decoder 0. +;; many -- a complex instruction may take an unspecified number of +;; cycles to decode in decoder 0. + +(define_attr "ppro_uops" "one,few,many" + (cond [(eq_attr "type" "other,multi,call,callv,fpspc,str") + (const_string "many") + (eq_attr "type" "icmov,fcmov,str,cld") + (const_string "few") + (eq_attr "type" "imov") + (if_then_else (eq_attr "memory" "store,both") + (const_string "few") + (const_string "one")) + (eq_attr "memory" "!none") + (const_string "few") + ] + (const_string "one"))) + +;; Rough readiness numbers. Fine tuning happens in i386.c. +;; +;; p0 describes port 0. +;; p01 describes ports 0 and 1 as a pair; alu insns can issue to either. +;; p2 describes port 2 for loads. +;; p34 describes ports 3 and 4 for stores. +;; fpu describes the fpu accessed via port 0. +;; ??? It is less than clear if there are separate fadd and fmul units +;; that could operate in parallel. +;; +;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real. + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "ishift,lea,ibr,cld")) + 1 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "imul")) + 4 1) + +;; ??? Does the divider lock out the pipe while it works, +;; or is there a disconnected unit? +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "idiv")) + 17 17) -;; Floating point +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fop,fop1,fsgn,fistp")) + 3 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fcmov")) + 2 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fcmp")) + 1 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fmov")) + 1 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fmul")) + 5 1) + +(define_function_unit "ppro_p0" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fdiv,fpspc")) + 56 1) + +(define_function_unit "ppro_p01" 2 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "!imov,fmov")) + 1 1) + +(define_function_unit "ppro_p01" 2 0 + (and (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "imov,fmov")) + (eq_attr "memory" "none")) + 1 1) + +(define_function_unit "ppro_p2" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (ior (eq_attr "type" "pop") + (eq_attr "memory" "load,both"))) + 3 1) + +(define_function_unit "ppro_p34" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (ior (eq_attr "type" "push") + (eq_attr "memory" "store,both"))) + 1 1) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fop,fop1,fsgn,fmov,fcmp,fcmov,fistp")) + 1 1) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fmul")) + 5 2) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "fdiv,fpspc")) + 56 56) + +;; imul uses the fpu. ??? does it have the same throughput as fmul? +(define_function_unit "fpu" 1 0 + (and (eq_attr "cpu" "pentiumpro") + (eq_attr "type" "imul")) + 4 1) + +;; AMD K6/K6-2 Scheduling +;; +;; The K6 has similar architecture to PPro. Important difference is, that +;; there are only two decoders and they seems to be much slower than execution +;; units. So we have to pay much more attention to proper decoding for +;; schedulers. We share most of scheduler code for PPro in i386.c +;; +;; The fp unit is not pipelined and do one operation per two cycles including +;; the FXCH. +;; +;; alu describes both ALU units (ALU-X and ALU-Y). +;; alux describes X alu unit +;; fpu describes FPU unit +;; load describes load unit. +;; branch describes branch unit. +;; store decsribes store unit. This unit is not modelled completely and only +;; used to model lea operation. Otherwise it lie outside of the critical +;; path. +;; +;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real. -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "i386,i486")) - 5 5) +;; The decoder specification is in the PPro section above! -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "pentium,pentiumpro")) - 3 0) +;; Shift instructions and certain arithmetic are issued only to X pipe. +(define_function_unit "k6_alux" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "ishift,alu1,negnot,cld")) + 1 1) -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium")) - 7 0) +;; The QI mode arithmetic is issued to X pipe only. +(define_function_unit "k6_alux" 1 0 + (and (eq_attr "cpu" "k6") + (and (eq_attr "type" "alu,alu1,negnot,icmp,test,imovx,incdec") + (match_operand:QI 0 "general_operand" ""))) + 1 1) -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro")) - 5 0) +(define_function_unit "k6_alu" 2 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "ishift,alu1,negnot,alu,icmp,test,imovx,incdec,setcc,lea")) + 1 1) -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro")) - 10 10) +(define_function_unit "k6_alu" 2 0 + (and (eq_attr "cpu" "k6") + (and (eq_attr "type" "imov") + (eq_attr "memory" "none"))) + 1 1) -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro")) - 6 0) +(define_function_unit "k6_branch" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "call,callv,ibr")) + 1 1) -(define_function_unit "fp" 1 0 - (eq_attr "type" "fpdiv") - 10 10) +;; Load unit have two cycle latency, but we take care for it in adjust_cost +(define_function_unit "k6_load" 1 0 + (and (eq_attr "cpu" "k6") + (ior (eq_attr "type" "pop") + (eq_attr "memory" "load,both"))) + 1 1) -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fld") (eq_attr "cpu" "!pentiumpro,k6")) - 1 0) +(define_function_unit "k6_load" 1 0 + (and (eq_attr "cpu" "k6") + (and (eq_attr "type" "str") + (eq_attr "memory" "load,both"))) + 10 10) -;; K6 FPU is not pipelined. -(define_function_unit "fp" 1 0 - (and (eq_attr "type" "fpop,fpmul,fcompare") (eq_attr "cpu" "k6")) - 2 2) +;; Lea have two instructions, so latency is probably 2 +(define_function_unit "k6_store" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "lea")) + 2 1) -;; i386 and i486 have one integer unit, which need not be modeled +(define_function_unit "k6_store" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "str")) + 10 10) -(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 "k6_store" 1 0 + (and (eq_attr "cpu" "k6") + (ior (eq_attr "type" "push") + (eq_attr "memory" "store,both"))) + 1 1) -(define_function_unit "integer" 2 0 +(define_function_unit "k6_fpu" 1 1 (and (eq_attr "cpu" "k6") - (and (eq_attr "type" "integer,binary,test,compare") - (eq_attr "memory" "!load"))) - 1 0) + (eq_attr "type" "fop,fop1,fmov,fcmp,fistp")) + 2 2) -;; Internally, K6 converts REG OP MEM instructions into a load (2 cycles) -;; and a register operation (1 cycle). -(define_function_unit "integer" 2 0 +(define_function_unit "k6_fpu" 1 1 (and (eq_attr "cpu" "k6") - (and (eq_attr "type" "integer,binary,test,compare") - (eq_attr "memory" "load"))) - 3 0) + (eq_attr "type" "fmul")) + 2 2) -;; Multiplies use one of the integer units -(define_function_unit "integer" 2 0 - (and (eq_attr "cpu" "pentium") (eq_attr "type" "imul")) - 11 11) +;; ??? Guess +(define_function_unit "k6_fpu" 1 1 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "fdiv,fpspc")) + 56 56) -(define_function_unit "integer" 2 0 - (and (eq_attr "cpu" "k6") (eq_attr "type" "imul")) +(define_function_unit "k6_alu" 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 "k6_alux" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "imul")) + 2 2) -(define_function_unit "integer" 2 0 - (and (eq_attr "cpu" "k6") (eq_attr "type" "idiv")) +;; ??? Guess +(define_function_unit "k6_alu" 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) - +(define_function_unit "k6_alux" 1 0 + (and (eq_attr "cpu" "k6") + (eq_attr "type" "idiv")) + 17 17) -;; "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". +;; AMD Athlon Scheduling ;; -;; 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); +;; The Athlon does contain three pipelined FP units, three integer units and +;; three address generation units. +;; +;; The predecode logic is determining boundaries of instructions in the 64 +;; byte cache line. So the cache line straddling problem of K6 might be issue +;; here as well, but it is not noted in the documentation. +;; +;; Three DirectPath instructions decoders and only one VectorPath decoder +;; is available. They can decode three DirectPath instructions or one VectorPath +;; instruction per cycle. +;; Decoded macro instructions are then passed to 72 entry instruction control +;; unit, that passes +;; it to the specialized integer (18 entry) and fp (36 entry) schedulers. +;; +;; The load/store queue unit is not attached to the schedulers but +;; communicates with all the execution units separately instead. + +(define_attr "athlon_decode" "direct,vector" + (cond [(eq_attr "type" "call,imul,idiv,other,multi,fcmov,fpspc,str,pop,cld,fcmov") + (const_string "vector") + (and (eq_attr "type" "push") + (match_operand 1 "memory_operand" "")) + (const_string "vector") + (and (eq_attr "type" "fmov") + (and (eq_attr "memory" "load,store") + (eq_attr "mode" "XF"))) + (const_string "vector")] + (const_string "direct"))) + +(define_function_unit "athlon_vectordec" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_decode" "vector")) + 1 1) + +(define_function_unit "athlon_directdec" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_decode" "direct")) + 1 1) + +(define_function_unit "athlon_vectordec" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_decode" "direct")) + 1 1 [(eq_attr "athlon_decode" "vector")]) + +(define_function_unit "athlon_ieu" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,ibr,call,callv,icmov,cld,pop,setcc,push,pop")) + 1 1) + +(define_function_unit "athlon_ieu" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "str")) + 15 15) + +(define_function_unit "athlon_ieu" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "imul")) + 5 0) + +(define_function_unit "athlon_ieu" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "idiv")) + 42 0) + +(define_function_unit "athlon_muldiv" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "imul")) + 5 0) + +(define_function_unit "athlon_muldiv" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "idiv")) + 42 42) + +(define_attr "athlon_fpunits" "none,store,mul,add,muladd,any" + (cond [(eq_attr "type" "fop,fop1,fcmp,fistp") + (const_string "add") + (eq_attr "type" "fmul,fdiv,fpspc,fsgn,fcmov") + (const_string "mul") + (and (eq_attr "type" "fmov") (eq_attr "memory" "store,both")) + (const_string "store") + (and (eq_attr "type" "fmov") (eq_attr "memory" "load")) + (const_string "any") + (and (eq_attr "type" "fmov") + (ior (match_operand:SI 1 "register_operand" "") + (match_operand 1 "immediate_operand" ""))) + (const_string "store") + (eq_attr "type" "fmov") + (const_string "muladd")] + (const_string "none"))) - operands[1] = const0_rtx; - return AS2 (cmp%W0,%1,%0); -}" - [(set_attr "type" "test")]) +;; We use latencies 1 for definitions. This is OK to model colisions +;; in execution units. The real latencies are modeled in the "fp" pipeline. + +;; fsin, fcos: 96-192 +;; fsincos: 107-211 +;; fsqrt: 19 for SFmode, 27 for DFmode, 35 for XFmode. +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "fpspc")) + 100 1) + +;; 16 cycles for SFmode, 20 for DFmode and 24 for XFmode. +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "fdiv")) + 24 1) + +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "fop,fop1,fmul,fistp")) + 4 1) + +;; XFmode loads are slow. +;; XFmode store is slow too (8 cycles), but we don't need to model it, because +;; there are no dependent instructions. + +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (and (eq_attr "type" "fmov") + (and (eq_attr "memory" "load") + (eq_attr "mode" "XF")))) + 10 1) + +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "fmov,fsgn")) + 2 1) + +;; fcmp and ftst instructions +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (and (eq_attr "type" "fcmp") + (eq_attr "athlon_decode" "direct"))) + 3 1) + +;; fcmpi instructions. +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (and (eq_attr "type" "fcmp") + (eq_attr "athlon_decode" "vector"))) + 3 1) + +(define_function_unit "athlon_fp" 3 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "type" "fcmov")) + 7 1) + +(define_function_unit "athlon_fp_mul" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_fpunits" "mul")) + 1 1) + +(define_function_unit "athlon_fp_add" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_fpunits" "add")) + 1 1) + +(define_function_unit "athlon_fp_muladd" 2 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_fpunits" "muladd,mul,add")) + 1 1) + +(define_function_unit "athlon_fp_store" 1 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "athlon_fpunits" "store")) + 1 1) + +;; We don't need to model the Address Generation Unit, since we don't model +;; the re-order buffer yet and thus we never schedule more than three operations +;; at time. Later we may want to experiment with MD_SCHED macros modeling the +;; decoders independently on the functional units. + +;(define_function_unit "athlon_agu" 3 0 +; (and (eq_attr "cpu" "athlon") +; (and (eq_attr "memory" "!none") +; (eq_attr "athlon_fpunits" "none"))) +; 1 1) + +;; Model load unit to avoid too long sequences of loads. We don't need to +;; model store queue, since it is hardly going to be bottleneck. + +(define_function_unit "athlon_load" 2 0 + (and (eq_attr "cpu" "athlon") + (eq_attr "memory" "load,both")) + 1 1) -(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); + +;; Compare instructions. - operands[1] = const0_rtx; - return AS2 (cmp%B0,%1,%0); -}" - [(set_attr "type" "test")]) +;; All compare insns have expanders that save the operands away without +;; actually generating RTL. The bCOND or sCOND (emitted immediately +;; after the cmp) will actually emit the cmpM. -(define_expand "tstqi" - [(set (cc0) - (match_operand:QI 0 "nonimmediate_operand" ""))] +(define_expand "cmpdi" + [(set (reg:CC 17) + (compare:CC (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "x86_64_general_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; + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[0] = force_reg (DImode, operands[0]); + ix86_compare_op0 = operands[0]; + ix86_compare_op1 = operands[1]; 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" "")))] + [(set (reg:CC 17) + (compare:CC (match_operand:SI 0 "cmpsi_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]; + ix86_compare_op0 = operands[0]; + ix86_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" "")))] + [(set (reg:CC 17) + (compare:CC (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]; + ix86_compare_op0 = operands[0]; + ix86_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" "")))] - "" - " + [(set (reg:CC 17) + (compare:CC (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "TARGET_QIMODE_MATH" { 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]; + ix86_compare_op0 = operands[0]; + ix86_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 "cmpdi_ccno_1_rex64" + [(set (reg 17) + (compare (match_operand:DI 0 "nonimmediate_operand" "r,?mr") + (match_operand:DI 1 "const0_operand" "n,n")))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "@ + test{q}\t{%0, %0|%0, %0} + cmp{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "test,icmp") + (set_attr "length_immediate" "0,1") + (set_attr "mode" "DI")]) + +(define_insn "*cmpdi_minus_1_rex64" + [(set (reg 17) + (compare (minus:DI (match_operand:DI 0 "nonimmediate_operand" "rm,r") + (match_operand:DI 1 "x86_64_general_operand" "re,mr")) + (const_int 0)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)" + "cmp{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "DI")]) + +(define_expand "cmpdi_1_rex64" + [(set (reg:CC 17) + (compare:CC (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" "")))] + "TARGET_64BIT" + "") -(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")]) +(define_insn "cmpdi_1_insn_rex64" + [(set (reg 17) + (compare (match_operand:DI 0 "nonimmediate_operand" "mr,r") + (match_operand:DI 1 "x86_64_general_operand" "re,mr")))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" + "cmp{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "DI")]) + + +(define_insn "*cmpsi_ccno_1" + [(set (reg 17) + (compare (match_operand:SI 0 "nonimmediate_operand" "r,?mr") + (match_operand:SI 1 "const0_operand" "n,n")))] + "ix86_match_ccmode (insn, CCNOmode)" + "@ + test{l}\t{%0, %0|%0, %0} + cmp{l}\t{%1, %0|%0, %1}" + [(set_attr "type" "test,icmp") + (set_attr "length_immediate" "0,1") + (set_attr "mode" "SI")]) + +(define_insn "*cmpsi_minus_1" + [(set (reg 17) + (compare (minus:SI (match_operand:SI 0 "nonimmediate_operand" "rm,r") + (match_operand:SI 1 "general_operand" "ri,mr")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCGOCmode)" + "cmp{l}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "SI")]) + +(define_expand "cmpsi_1" + [(set (reg:CC 17) + (compare:CC (match_operand:SI 0 "nonimmediate_operand" "rm,r") + (match_operand:SI 1 "general_operand" "ri,mr")))] + "" + "") -;; 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_insn "*cmpsi_1_insn" + [(set (reg 17) + (compare (match_operand:SI 0 "nonimmediate_operand" "rm,r") + (match_operand:SI 1 "general_operand" "ri,mr")))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && ix86_match_ccmode (insn, CCmode)" + "cmp{l}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "SI")]) + +(define_insn "*cmphi_ccno_1" + [(set (reg 17) + (compare (match_operand:HI 0 "nonimmediate_operand" "r,?mr") + (match_operand:HI 1 "const0_operand" "n,n")))] + "ix86_match_ccmode (insn, CCNOmode)" + "@ + test{w}\t{%0, %0|%0, %0} + cmp{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "test,icmp") + (set_attr "length_immediate" "0,1") + (set_attr "mode" "HI")]) + +(define_insn "*cmphi_minus_1" + [(set (reg 17) + (compare (minus:HI (match_operand:HI 0 "nonimmediate_operand" "rm,r") + (match_operand:HI 1 "general_operand" "ri,mr")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCGOCmode)" + "cmp{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "HI")]) + +(define_insn "*cmphi_1" + [(set (reg 17) + (compare (match_operand:HI 0 "nonimmediate_operand" "rm,r") + (match_operand:HI 1 "general_operand" "ri,mr")))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && ix86_match_ccmode (insn, CCmode)" + "cmp{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "HI")]) + +(define_insn "*cmpqi_ccno_1" + [(set (reg 17) + (compare (match_operand:QI 0 "nonimmediate_operand" "q,?mq") + (match_operand:QI 1 "const0_operand" "n,n")))] + "ix86_match_ccmode (insn, CCNOmode)" + "@ + test{b}\t{%0, %0|%0, %0} + cmp{b}\t{$0, %0|%0, 0}" + [(set_attr "type" "test,icmp") + (set_attr "length_immediate" "0,1") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_1" + [(set (reg 17) + (compare (match_operand:QI 0 "nonimmediate_operand" "qm,q") + (match_operand:QI 1 "general_operand" "qi,mq")))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_minus_1" + [(set (reg 17) + (compare (minus:QI (match_operand:QI 0 "nonimmediate_operand" "qm,q") + (match_operand:QI 1 "general_operand" "qi,mq")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCGOCmode)" + "cmp{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_ext_1" + [(set (reg 17) + (compare + (match_operand:QI 0 "general_operand" "Qm") + (subreg:QI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0)))] + "!TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%h1, %0|%0, %h1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_ext_1_rex64" + [(set (reg 17) + (compare + (match_operand:QI 0 "register_operand" "Q") + (subreg:QI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%h1, %0|%0, %h1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_ext_2" + [(set (reg 17) + (compare + (subreg:QI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "const0_operand" "n")))] + "ix86_match_ccmode (insn, CCNOmode)" + "test{b}\t%h0, %h0" + [(set_attr "type" "test") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) + +(define_expand "cmpqi_ext_3" + [(set (reg:CC 17) + (compare:CC + (subreg:QI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "general_operand" "")))] + "" + "") + +(define_insn "cmpqi_ext_3_insn" + [(set (reg 17) + (compare + (subreg:QI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "general_operand" "Qmn")))] + "!TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%1, %h0|%h0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "cmpqi_ext_3_insn_rex64" + [(set (reg 17) + (compare + (subreg:QI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "nonmemory_operand" "Qn")))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%1, %h0|%h0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +(define_insn "*cmpqi_ext_4" + [(set (reg 17) + (compare + (subreg:QI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0) + (subreg:QI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) 0)))] + "ix86_match_ccmode (insn, CCmode)" + "cmp{b}\t{%h1, %h0|%h0, %h1}" + [(set_attr "type" "icmp") + (set_attr "mode" "QI")]) + +;; These implement float point compares. +;; %%% See if we can get away with VOIDmode operands on the actual insns, +;; which would allow mix and match FP modes on the compares. Which is what +;; the old patterns did, but with many more of them. (define_expand "cmpxf" - [(set (cc0) - (compare (match_operand:XF 0 "register_operand" "") - (match_operand:XF 1 "register_operand" "")))] + [(set (reg:CC 17) + (compare:CC (match_operand:XF 0 "cmp_fp_expander_operand" "") + (match_operand:XF 1 "cmp_fp_expander_operand" "")))] + "!TARGET_64BIT && TARGET_80387" +{ + ix86_compare_op0 = operands[0]; + ix86_compare_op1 = operands[1]; + DONE; +}) + +(define_expand "cmptf" + [(set (reg:CC 17) + (compare:CC (match_operand:TF 0 "cmp_fp_expander_operand" "") + (match_operand:TF 1 "cmp_fp_expander_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]; + ix86_compare_op0 = operands[0]; + ix86_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" - " + [(set (reg:CC 17) + (compare:CC (match_operand:DF 0 "cmp_fp_expander_operand" "") + (match_operand:DF 1 "cmp_fp_expander_operand" "")))] + "TARGET_80387 || TARGET_SSE2" { - 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]; + ix86_compare_op0 = operands[0]; + ix86_compare_op1 = operands[1]; DONE; -}") +}) (define_expand "cmpsf" - [(set (cc0) - (compare (match_operand:SF 0 "register_operand" "") - (match_operand:SF 1 "general_operand" "")))] - "TARGET_80387" - " + [(set (reg:CC 17) + (compare:CC (match_operand:SF 0 "cmp_fp_expander_operand" "") + (match_operand:SF 1 "cmp_fp_expander_operand" "")))] + "TARGET_80387 || TARGET_SSE" { - 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]; + ix86_compare_op0 = operands[0]; + ix86_compare_op1 = 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" - "") +;; FP compares, step 1: +;; Set the FP condition codes. +;; +;; CCFPmode compare with exceptions +;; CCFPUmode compare with no exceptions -(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" - "") +;; %%% It is an unfortunate fact that ftst has no non-popping variant, +;; and that fp moves clobber the condition codes, and that there is +;; currently no way to describe this fact to reg-stack. So there are +;; no splitters yet for this. -(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" - "") +;; %%% YIKES! This scheme does not retain a strong connection between +;; the real compare and the ultimate cc0 user, so CC_REVERSE does not +;; work! Only allow tos/mem with tos in op 0. +;; +;; Hmm, of course, this is what the actual _hardware_ does. Perhaps +;; things aren't as bad as they sound... -(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" - " +(define_insn "*cmpfp_0" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP (match_operand 1 "register_operand" "f") + (match_operand 2 "const0_operand" "X"))] 9))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2])" { - 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 ""))])] + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "ftst\;fnstsw\t%0\;fstp\t%y0"; + else + return "ftst\;fnstsw\t%0"; +} + [(set_attr "type" "multi") + (set_attr "mode" "unknownfp")]) + +;; We may not use "#" to split and emit these, since the REG_DEAD notes +;; used to manage the reg stack popping would not be preserved. + +(define_insn "*cmpfp_2_sf" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "nonimmediate_operand" "fm")))] "TARGET_80387" - "") + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "SF")]) -(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 ""))])] +(define_insn "*cmpfp_2_sf_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP + (match_operand:SF 1 "register_operand" "f") + (match_operand:SF 2 "nonimmediate_operand" "fm"))] 9))] "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); + "* return output_fp_compare (insn, operands, 2, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "SF")]) + +(define_insn "*cmpfp_2_df" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "nonimmediate_operand" "fm")))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "DF")]) - 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); - } - } - } +(define_insn "*cmpfp_2_df_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP + (match_operand:DF 1 "register_operand" "f") + (match_operand:DF 2 "nonimmediate_operand" "fm"))] 9))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 2, 0);" + [(set_attr "type" "multi") + (set_attr "mode" "DF")]) + +(define_insn "*cmpfp_2_xf" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")))] + "!TARGET_64BIT && TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "XF")]) + +(define_insn "*cmpfp_2_tf" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:TF 0 "register_operand" "f") + (match_operand:TF 1 "register_operand" "f")))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 0, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "XF")]) - /* 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); +(define_insn "*cmpfp_2_xf_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP + (match_operand:XF 1 "register_operand" "f") + (match_operand:XF 2 "register_operand" "f"))] 9))] + "!TARGET_64BIT && TARGET_80387" + "* return output_fp_compare (insn, operands, 2, 0);" + [(set_attr "type" "multi") + (set_attr "mode" "XF")]) + +(define_insn "*cmpfp_2_tf_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFP + (match_operand:TF 1 "register_operand" "f") + (match_operand:TF 2 "register_operand" "f"))] 9))] + "TARGET_80387" + "* return output_fp_compare (insn, operands, 2, 0);" + [(set_attr "type" "multi") + (set_attr "mode" "XF")]) + +(define_insn "*cmpfp_2u" + [(set (reg:CCFPU 18) + (compare:CCFPU + (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "* return output_fp_compare (insn, operands, 0, 1);" + [(set_attr "type" "fcmp") + (set_attr "mode" "unknownfp")]) - if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) - return AS2 (test%W0,%1,%0); +(define_insn "*cmpfp_2u_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(compare:CCFPU + (match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f"))] 9))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2])" + "* return output_fp_compare (insn, operands, 2, 1);" + [(set_attr "type" "multi") + (set_attr "mode" "unknownfp")]) - return AS2 (test%W1,%0,%1); -}" - [(set_attr "type" "compare")]) +;; Patterns to match the SImode-in-memory ficom instructions. +;; +;; %%% Play games with accepting gp registers, as otherwise we have to +;; force them to memory during rtl generation, which is no good. We +;; can get rid of this once we teach reload to do memory input reloads +;; via pushes. + +(define_insn "*ficom_1" + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand 0 "register_operand" "f,f") + (float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))] + "0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])" + "#") -(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); +;; Split the not-really-implemented gp register case into a +;; push-op-pop sequence. +;; +;; %%% This is most efficient, but am I gonna get in trouble +;; for separating cc0_setter and cc0_user? - return AS2 (test%B1,%0,%1); -}" - [(set_attr "type" "compare")]) +(define_split + [(set (reg:CCFP 18) + (compare:CCFP + (match_operand:SF 0 "register_operand" "") + (float (match_operand:SI 1 "register_operand" ""))))] + "0 && TARGET_80387 && reload_completed" + [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1)) + (set (reg:CCFP 18) (compare:CCFP (match_dup 0) (match_dup 2))) + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx); + operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);") + +;; FP compares, step 2 +;; Move the fpsw to ax. + +(define_insn "x86_fnstsw_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI [(reg 18)] 9))] + "TARGET_80387" + "fnstsw\t%0" + [(set_attr "length" "2") + (set_attr "mode" "SI") + (set_attr "i387" "1") + (set_attr "ppro_uops" "few")]) + +;; FP compares, step 3 +;; Get ax into flags, general case. + +(define_insn "x86_sahf_1" + [(set (reg:CC 17) + (unspec:CC [(match_operand:HI 0 "register_operand" "a")] 10))] + "!TARGET_64BIT" + "sahf" + [(set_attr "length" "1") + (set_attr "athlon_decode" "vector") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "one")]) + +;; Pentium Pro can do steps 1 through 3 in one go. + +(define_insn "*cmpfp_i" + [(set (reg:CCFP 17) + (compare:CCFP (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] + "TARGET_80387 && TARGET_CMOVE + && !SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[0])" + "* return output_fp_compare (insn, operands, 1, 0);" + [(set_attr "type" "fcmp") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_i_sse" + [(set (reg:CCFP 17) + (compare:CCFP (match_operand 0 "register_operand" "f#x,x#f") + (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))] + "TARGET_80387 + && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[0])" + "* return output_fp_compare (insn, operands, 1, 0);" + [(set_attr "type" "fcmp,sse") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_i_sse_only" + [(set (reg:CCFP 17) + (compare:CCFP (match_operand 0 "register_operand" "x") + (match_operand 1 "nonimmediate_operand" "xm")))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[0])" + "* return output_fp_compare (insn, operands, 1, 0);" + [(set_attr "type" "sse") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_iu" + [(set (reg:CCFPU 17) + (compare:CCFPU (match_operand 0 "register_operand" "f") + (match_operand 1 "register_operand" "f")))] + "TARGET_80387 && TARGET_CMOVE + && !SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "* return output_fp_compare (insn, operands, 1, 1);" + [(set_attr "type" "fcmp") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_iu_sse" + [(set (reg:CCFPU 17) + (compare:CCFPU (match_operand 0 "register_operand" "f#x,x#f") + (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))] + "TARGET_80387 + && SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "* return output_fp_compare (insn, operands, 1, 1);" + [(set_attr "type" "fcmp,sse") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) + +(define_insn "*cmpfp_iu_sse_only" + [(set (reg:CCFPU 17) + (compare:CCFPU (match_operand 0 "register_operand" "x") + (match_operand 1 "nonimmediate_operand" "xm")))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[0])) + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "* return output_fp_compare (insn, operands, 1, 1);" + [(set_attr "type" "sse") + (set_attr "mode" "unknownfp") + (set_attr "athlon_decode" "vector")]) -;; 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")]) +;; Move instructions. ;; 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" "") + [(set (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "general_operand" ""))] "" - " -{ - extern int flag_pic; + "ix86_expand_move (SImode, operands); DONE;") - 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. +;; Push/pop instructions. They are separate since autoinc/dec is not a +;; general_operand. +;; +;; %%% We don't use a post-inc memory reference because x86 is not a +;; general AUTO_INC_DEC host, which impacts how it is treated in flow. +;; Changing this impacts compiler performance on other non-AUTO_INC_DEC +;; targets without our curiosities, and it is just as easy to represent +;; this differently. -(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" - "* +(define_insn "*pushsi2" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "general_no_elim_operand" "ri*m"))] + "!TARGET_64BIT" + "push{l}\t%1" + [(set_attr "type" "push") + (set_attr "mode" "SI")]) + +;; For 64BIT abi we always round up to 8 bytes. +(define_insn "*pushsi2_rex64" + [(set (match_operand:SI 0 "push_operand" "=X") + (match_operand:SI 1 "nonmemory_no_elim_operand" "ri"))] + "TARGET_64BIT" + "push{q}\t%q1" + [(set_attr "type" "push") + (set_attr "mode" "SI")]) + +(define_insn "*pushsi2_prologue" + [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "general_no_elim_operand" "ri*m")) + (clobber (mem:BLK (scratch)))] + "!TARGET_64BIT" + "push{l}\t%1" + [(set_attr "type" "push") + (set_attr "mode" "SI")]) + +(define_insn "*popsi1_epilogue" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") + (mem:SI (reg:SI 7))) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (const_int 4))) + (clobber (mem:BLK (scratch)))] + "!TARGET_64BIT" + "pop{l}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "SI")]) + +(define_insn "popsi1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") + (mem:SI (reg:SI 7))) + (set (reg:SI 7) + (plus:SI (reg:SI 7) (const_int 4)))] + "!TARGET_64BIT" + "pop{l}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "SI")]) + +(define_insn "*movsi_xor" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "const0_operand" "i")) + (clobber (reg:CC 17))] + "reload_completed && (!TARGET_USE_MOV0 || optimize_size)" + "xor{l}\t{%0, %0|%0, %0}" + [(set_attr "type" "alu1") + (set_attr "mode" "SI") + (set_attr "length_immediate" "0")]) + +(define_insn "*movsi_or" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "immediate_operand" "i")) + (clobber (reg:CC 17))] + "reload_completed && GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1 + && (TARGET_PENTIUM || optimize_size)" { - 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" - "* + operands[1] = constm1_rtx; + return "or{l}\t{%1, %0|%0, %1}"; +} + [(set_attr "type" "alu1") + (set_attr "mode" "SI") + (set_attr "length_immediate" "1")]) + +(define_insn "*movsi_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=*a,r,*a,m,!*y,!rm,!*Y,!rm,!*Y") + (match_operand:SI 1 "general_operand" "im,rinm,rinm,rin,rm,*y,rm,*Y,*Y"))] + "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%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")]) + switch (get_attr_type (insn)) + { + case TYPE_SSE: + if (get_attr_mode (insn) == TImode) + return "movdqa\t{%1, %0|%0, %1}"; + return "movd\t{%1, %0|%0, %1}"; -(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")]) + case TYPE_MMX: + return "movd\t{%1, %0|%0, %1}"; -;; On i486, an incl and movl are both faster than incw and movw. + case TYPE_LEA: + return "lea{l}\t{%1, %0|%0, %1}"; + + default: + if (flag_pic && SYMBOLIC_CONST (operands[1])) + abort(); + return "mov{l}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "4,5") + (const_string "mmx") + (eq_attr "alternative" "6,7,8") + (const_string "sse") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:SI 1 "symbolic_operand" "")) + (const_string "lea") + ] + (const_string "imov"))) + (set_attr "modrm" "0,*,0,*,*,*,*,*,*") + (set_attr "mode" "SI,SI,SI,SI,SI,SI,TI,SI,SI")]) + +;; Stores and loads of ax to arbitary constant address. +;; We fake an second form of instruction to force reload to load address +;; into register when rax is not available +(define_insn "*movabssi_1_rex64" + [(set (mem:SI (match_operand:DI 0 "x86_64_movabs_operand" "i,r,r")) + (match_operand:SI 1 "nonmemory_operand" "a,er,i"))] + "TARGET_64BIT" + "@ + movabs{l}\t{%1, %P0|%P0, %1} + mov{l}\t{%1, %a0|%a0, %1} + movabs{l}\t{%1, %a0|%a0, %1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*,*") + (set_attr "length_address" "8,0,0") + (set_attr "length_immediate" "0,*,*") + (set_attr "memory" "store") + (set_attr "mode" "SI")]) + +(define_insn "*movabssi_2_rex64" + [(set (match_operand:SI 0 "register_operand" "=a,r") + (mem:SI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] + "TARGET_64BIT" + "@ + movabs{l}\t{%P1, %0|%0, %P1} + mov{l}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0") + (set_attr "memory" "load") + (set_attr "mode" "SI")]) + +(define_insn "*swapsi" + [(set (match_operand:SI 0 "register_operand" "+r") + (match_operand:SI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "" + "xchg{l}\t%1, %0" + [(set_attr "type" "imov") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "mode" "SI") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) (define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] "" - " + "ix86_expand_move (HImode, operands); DONE;") + +(define_insn "*pushhi2" + [(set (match_operand:HI 0 "push_operand" "=<,<") + (match_operand:HI 1 "general_no_elim_operand" "n,r*m"))] + "!TARGET_64BIT" + "@ + push{w}\t{|WORD PTR }%1 + push{w}\t%1" + [(set_attr "type" "push") + (set_attr "mode" "HI")]) + +;; For 64BIT abi we always round up to 8 bytes. +(define_insn "*pushhi2_rex64" + [(set (match_operand:HI 0 "push_operand" "=X") + (match_operand:HI 1 "nonmemory_no_elim_operand" "ri"))] + "TARGET_64BIT" + "push{q}\t%q1" + [(set_attr "type" "push") + (set_attr "mode" "QI")]) + +(define_insn "*movhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=*a,r,r,*a,r,m") + (match_operand:HI 1 "general_operand" "i,r,rn,rm,rm,rn"))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" { - /* 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) + switch (get_attr_type (insn)) { - operands[1] = force_reg (HImode, operands[1]); + case TYPE_IMOVX: + /* movzwl is faster than movw on p2 due to partial word stalls, + though not as fast as an aligned movl. */ + return "movz{wl|x}\t{%1, %k0|%k0, %1}"; + default: + if (get_attr_mode (insn) == MODE_SI) + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else + return "mov{w}\t{%1, %0|%0, %1}"; } -}") +} + [(set (attr "type") + (cond [(and (eq_attr "alternative" "0,1") + (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_HIMODE_MATH") + (const_int 0)))) + (const_string "imov") + (and (eq_attr "alternative" "2,3,4") + (match_operand:HI 1 "aligned_operand" "")) + (const_string "imov") + (and (ne (symbol_ref "TARGET_MOVX") + (const_int 0)) + (eq_attr "alternative" "0,1,3,4")) + (const_string "imovx") + ] + (const_string "imov"))) + (set (attr "mode") + (cond [(eq_attr "type" "imovx") + (const_string "SI") + (and (eq_attr "alternative" "2,3,4") + (match_operand:HI 1 "aligned_operand" "")) + (const_string "SI") + (and (eq_attr "alternative" "0,1") + (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_HIMODE_MATH") + (const_int 0)))) + (const_string "SI") + ] + (const_string "HI"))) + (set_attr "modrm" "0,*,*,0,*,*")]) + +;; Stores and loads of ax to arbitary constant address. +;; We fake an second form of instruction to force reload to load address +;; into register when rax is not available +(define_insn "*movabshi_1_rex64" + [(set (mem:HI (match_operand:DI 0 "x86_64_movabs_operand" "i,r,r")) + (match_operand:HI 1 "nonmemory_operand" "a,er,i"))] + "TARGET_64BIT" + "@ + movabs{w}\t{%1, %P0|%P0, %1} + mov{w}\t{%1, %a0|%a0, %1} + movabs{w}\t{%1, %a0|%a0, %1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*,*") + (set_attr "length_address" "8,0,0") + (set_attr "length_immediate" "0,*,*") + (set_attr "memory" "store") + (set_attr "mode" "HI")]) + +(define_insn "*movabshi_2_rex64" + [(set (match_operand:HI 0 "register_operand" "=a,r") + (mem:HI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] + "TARGET_64BIT" + "@ + movabs{w}\t{%P1, %0|%0, %P1} + mov{w}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0") + (set_attr "memory" "load") + (set_attr "mode" "HI")]) + +(define_insn "*swaphi_1" + [(set (match_operand:HI 0 "register_operand" "+r") + (match_operand:HI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "TARGET_PARTIAL_REG_STALL" + "xchg{w}\t%1, %0" + [(set_attr "type" "imov") + (set_attr "pent_pair" "np") + (set_attr "mode" "HI") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) + +(define_insn "*swaphi_2" + [(set (match_operand:HI 0 "register_operand" "+r") + (match_operand:HI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "! TARGET_PARTIAL_REG_STALL" + "xchg{l}\t%k1, %k0" + [(set_attr "type" "imov") + (set_attr "pent_pair" "np") + (set_attr "mode" "SI") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) -(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)" - "* +(define_expand "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "")) + (match_operand:HI 1 "general_operand" ""))] + "! TARGET_PARTIAL_REG_STALL || optimize_size" { - 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 - } - } + /* Don't generate memory->memory moves, go through a register */ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (HImode, operands[1]); +}) - return AS2 (mov%W0,%1,%0); -}" - [(set_attr "type" "integer,memory") - (set_attr "memory" "*,load")]) +(define_insn "*movstricthi_1" + [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+rm,r")) + (match_operand:HI 1 "general_operand" "rn,m"))] + "(! TARGET_PARTIAL_REG_STALL || optimize_size) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "mov{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "imov") + (set_attr "mode" "HI")]) + +(define_insn "*movstricthi_xor" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r")) + (match_operand:HI 1 "const0_operand" "i")) + (clobber (reg:CC 17))] + "reload_completed + && ((!TARGET_USE_MOV0 && !TARGET_PARTIAL_REG_STALL) || optimize_size)" + "xor{w}\t{%0, %0|%0, %0}" + [(set_attr "type" "alu1") + (set_attr "mode" "HI") + (set_attr "length_immediate" "0")]) -(define_expand "movstricthi" - [(set (strict_low_part (match_operand:HI 0 "general_operand" "")) - (match_operand:HI 1 "general_operand" ""))] +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] "" - " + "ix86_expand_move (QImode, operands); DONE;") + +;; 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 "*pushqi2" + [(set (match_operand:QI 0 "push_operand" "=X,X") + (match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))] + "!TARGET_64BIT" + "@ + push{w}\t{|word ptr }%1 + push{w}\t%w1" + [(set_attr "type" "push") + (set_attr "mode" "HI")]) + +;; For 64BIT abi we always round up to 8 bytes. +(define_insn "*pushqi2_rex64" + [(set (match_operand:QI 0 "push_operand" "=X") + (match_operand:QI 1 "nonmemory_no_elim_operand" "ri"))] + "TARGET_64BIT" + "push{q}\t%q1" + [(set_attr "type" "push") + (set_attr "mode" "QI")]) + +;; Situation is quite tricky about when to choose full sized (SImode) move +;; over QImode moves. For Q_REG -> Q_REG move we use full size only for +;; partial register dependency machines (such as AMD Athlon), where QImode +;; moves issue extra dependency and for partial register stalls machines +;; that don't use QImode patterns (and QImode move cause stall on the next +;; instruction). +;; +;; For loads of Q_REG to NONQ_REG we use full sized moves except for partial +;; register stall machines with, where we use QImode instructions, since +;; partial register stall can be caused there. Then we use movzx. +(define_insn "*movqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q ,q ,r,r ,?r,m") + (match_operand:QI 1 "general_operand" " q,qn,qm,q,rn,qm,qn"))] + "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" { - /* 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) + switch (get_attr_type (insn)) { - operands[1] = force_reg (HImode, operands[1]); + case TYPE_IMOVX: + if (!ANY_QI_REG_P (operands[1]) && GET_CODE (operands[1]) != MEM) + abort (); + return "movz{bl|x}\t{%1, %k0|%k0, %1}"; + default: + if (get_attr_mode (insn) == MODE_SI) + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else + return "mov{b}\t{%1, %0|%0, %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"))] +} + [(set (attr "type") + (cond [(and (eq_attr "alternative" "3") + (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_QIMODE_MATH") + (const_int 0)))) + (const_string "imov") + (eq_attr "alternative" "3,5") + (const_string "imovx") + (and (ne (symbol_ref "TARGET_MOVX") + (const_int 0)) + (eq_attr "alternative" "2")) + (const_string "imovx") + ] + (const_string "imov"))) + (set (attr "mode") + (cond [(eq_attr "alternative" "3,4,5") + (const_string "SI") + (eq_attr "alternative" "6") + (const_string "QI") + (eq_attr "type" "imovx") + (const_string "SI") + (and (eq_attr "type" "imov") + (and (eq_attr "alternative" "0,1,2") + (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY") + (const_int 0)))) + (const_string "SI") + ;; Avoid partial register stalls when not using QImode arithmetic + (and (eq_attr "type" "imov") + (and (eq_attr "alternative" "0,1,2") + (and (ne (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_QIMODE_MATH") + (const_int 0))))) + (const_string "SI") + ] + (const_string "QI")))]) + +(define_expand "reload_outqi" + [(parallel [(match_operand:QI 0 "" "=m") + (match_operand:QI 1 "register_operand" "r") + (match_operand:QI 2 "register_operand" "=&q")])] "" - "* { - operands[1] = gen_rtx_REG (HImode, REGNO (operands[1])); - return AS1 (push%W0,%1); -}") + rtx op0, op1, op2; + op0 = operands[0]; op1 = operands[1]; op2 = operands[2]; -;; On i486, incb reg is faster than movb $1,reg. + if (reg_overlap_mentioned_p (op2, op0)) + abort (); + if (! q_regs_operand (op1, QImode)) + { + emit_insn (gen_movqi (op2, op1)); + op1 = op2; + } + emit_insn (gen_movqi (op0, op1)); + DONE; +}) -;; ??? Do a recognizer for zero_extract that looks just like this, but reads -;; or writes %ah, %bh, %ch, %dh. +(define_insn "*swapqi" + [(set (match_operand:QI 0 "register_operand" "+r") + (match_operand:QI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "" + "xchg{b}\t%1, %0" + [(set_attr "type" "imov") + (set_attr "pent_pair" "np") + (set_attr "mode" "QI") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") +(define_expand "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) (match_operand:QI 1 "general_operand" ""))] + "! TARGET_PARTIAL_REG_STALL" +{ + /* Don't generate memory->memory moves, go through a register. */ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (QImode, operands[1]); +}) + +(define_insn "*movstrictqi_1" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) + (match_operand:QI 1 "general_operand" "*qn,m"))] + "! TARGET_PARTIAL_REG_STALL + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "mov{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "imov") + (set_attr "mode" "QI")]) + +(define_insn "*movstrictqi_xor" + [(set (strict_low_part (match_operand:QI 0 "q_regs_operand" "+q")) + (match_operand:QI 1 "const0_operand" "i")) + (clobber (reg:CC 17))] + "reload_completed && (!TARGET_USE_MOV0 || optimize_size)" + "xor{b}\t{%0, %0|%0, %0}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI") + (set_attr "length_immediate" "0")]) + +(define_insn "*movsi_extv_1" + [(set (match_operand:SI 0 "register_operand" "=R") + (sign_extract:SI (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))] "" - " + "movs{bl|x}\t{%h1, %0|%0, %h1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) + +(define_insn "*movhi_extv_1" + [(set (match_operand:HI 0 "register_operand" "=R") + (sign_extract:HI (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))] + "" + "movs{bl|x}\t{%h1, %k0|%k0, %h1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) + +(define_insn "*movqi_extv_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?r") + (sign_extract:QI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)))] + "!TARGET_64BIT" { - /* 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) + switch (get_attr_type (insn)) { - operands[1] = force_reg (QImode, operands[1]); + case TYPE_IMOVX: + return "movs{bl|x}\t{%h1, %k0|%k0, %h1}"; + default: + return "mov{b}\t{%h1, %0|%0, %h1}"; } -}") - -(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)" - "* +} + [(set (attr "type") + (if_then_else (and (match_operand:QI 0 "register_operand" "") + (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0)))) + (const_string "imovx") + (const_string "imov"))) + (set (attr "mode") + (if_then_else (eq_attr "type" "imovx") + (const_string "SI") + (const_string "QI")))]) + +(define_insn "*movqi_extv_1_rex64" + [(set (match_operand:QI 0 "register_operand" "=Q,?R") + (sign_extract:QI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)))] + "TARGET_64BIT" { - 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); + switch (get_attr_type (insn)) + { + case TYPE_IMOVX: + return "movs{bl|x}\t{%h1, %k0|%k0, %h1}"; + default: + return "mov{b}\t{%h1, %0|%0, %h1}"; } - - /* 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" ""))] +} + [(set (attr "type") + (if_then_else (and (match_operand:QI 0 "register_operand" "") + (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0)))) + (const_string "imovx") + (const_string "imov"))) + (set (attr "mode") + (if_then_else (eq_attr "type" "imovx") + (const_string "SI") + (const_string "QI")))]) + +;; Stores and loads of ax to arbitary constant address. +;; We fake an second form of instruction to force reload to load address +;; into register when rax is not available +(define_insn "*movabsqi_1_rex64" + [(set (mem:QI (match_operand:DI 0 "x86_64_movabs_operand" "i,r,r")) + (match_operand:QI 1 "nonmemory_operand" "a,er,i"))] + "TARGET_64BIT" + "@ + movabs{b}\t{%1, %P0|%P0, %1} + mov{b}\t{%1, %a0|%a0, %1} + movabs{b}\t{%1, %a0|%a0, %1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*,*") + (set_attr "length_address" "8,0,0") + (set_attr "length_immediate" "0,*,*") + (set_attr "memory" "store") + (set_attr "mode" "QI")]) + +(define_insn "*movabsqi_2_rex64" + [(set (match_operand:QI 0 "register_operand" "=a,r") + (mem:QI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] + "TARGET_64BIT" + "@ + movabs{b}\t{%P1, %0|%0, %P1} + mov{b}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0") + (set_attr "memory" "load") + (set_attr "mode" "QI")]) + +(define_insn "*movsi_extzv_1" + [(set (match_operand:SI 0 "register_operand" "=R") + (zero_extract:SI (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))] "" - " + "movz{bl|x}\t{%h1, %0|%0, %h1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) + +(define_insn "*movqi_extzv_2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?R") + (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0))] + "!TARGET_64BIT" { - /* 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) + switch (get_attr_type (insn)) { - operands[1] = force_reg (QImode, operands[1]); + case TYPE_IMOVX: + return "movz{bl|x}\t{%h1, %k0|%k0, %h1}"; + default: + return "mov{b}\t{%h1, %0|%0, %h1}"; } -}") - -(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)" - "* +} + [(set (attr "type") + (if_then_else (and (match_operand:QI 0 "register_operand" "") + (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0)))) + (const_string "imovx") + (const_string "imov"))) + (set (attr "mode") + (if_then_else (eq_attr "type" "imovx") + (const_string "SI") + (const_string "QI")))]) + +(define_insn "*movqi_extzv_2_rex64" + [(set (match_operand:QI 0 "register_operand" "=Q,?R") + (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0))] + "TARGET_64BIT" { - rtx link; + switch (get_attr_type (insn)) + { + case TYPE_IMOVX: + return "movz{bl|x}\t{%h1, %k0|%k0, %h1}"; + default: + return "mov{b}\t{%h1, %0|%0, %h1}"; + } +} + [(set (attr "type") + (if_then_else (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0))) + (const_string "imovx") + (const_string "imov"))) + (set (attr "mode") + (if_then_else (eq_attr "type" "imovx") + (const_string "SI") + (const_string "QI")))]) + +(define_insn "movsi_insv_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") + (const_int 8) + (const_int 8)) + (match_operand:SI 1 "general_operand" "Qmn"))] + "!TARGET_64BIT" + "mov{b}\t{%b1, %h0|%h0, %b1}" + [(set_attr "type" "imov") + (set_attr "mode" "QI")]) + +(define_insn "*movsi_insv_1_rex64" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") + (const_int 8) + (const_int 8)) + (match_operand:SI 1 "nonmemory_operand" "Qn"))] + "TARGET_64BIT" + "mov{b}\t{%b1, %h0|%h0, %b1}" + [(set_attr "type" "imov") + (set_attr "mode" "QI")]) + +(define_insn "*movqi_insv_2" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") + (const_int 8) + (const_int 8)) + (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "Q") + (const_int 8)) + (const_int 255)))] + "" + "mov{b}\t{%h1, %h0|%h0, %h1}" + [(set_attr "type" "imov") + (set_attr "mode" "QI")]) - /* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8. */ +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + "ix86_expand_move (DImode, operands); DONE;") - 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); +(define_insn "*pushdi" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_no_elim_operand" "riF*m"))] + "!TARGET_64BIT" + "#") - /* 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)); - } +(define_insn "pushdi2_rex64" + [(set (match_operand:DI 0 "push_operand" "=<,!<") + (match_operand:DI 1 "general_no_elim_operand" "re*m,n"))] + "TARGET_64BIT" + "@ + push{q}\t%1 + #" + [(set_attr "type" "push,multi") + (set_attr "mode" "DI")]) + +;; Convert impossible pushes of immediate to existing instructions. +;; First try to get scratch register and go through it. In case this +;; fails, push sign extended lower part first and then overwrite +;; upper part by 32bit move. +(define_peephole2 + [(match_scratch:DI 2 "r") + (set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") - return AS2 (mov%B0,%1,%0); -}") +;; We need to define this as both peepholer and splitter for case +;; peephole2 pass is not run. +(define_peephole2 + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode) && 1" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] + "split_di (operands + 1, 1, operands + 2, operands + 3); + operands[1] = gen_lowpart (DImode, operands[2]); + operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (4))); + ") -(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" - "* +(define_split + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && (flow2_completed || (reload_completed && !flag_peephole2)) + && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] + "split_di (operands + 1, 1, operands + 2, operands + 3); + operands[1] = gen_lowpart (DImode, operands[2]); + operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (4))); + ") + +(define_insn "*pushdi2_prologue_rex64" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_no_elim_operand" "re*m")) + (clobber (mem:BLK (scratch)))] + "TARGET_64BIT" + "push{q}\t%1" + [(set_attr "type" "push") + (set_attr "mode" "DI")]) + +(define_insn "*popdi1_epilogue_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") + (mem:DI (reg:DI 7))) + (set (reg:DI 7) + (plus:DI (reg:DI 7) (const_int 8))) + (clobber (mem:BLK (scratch)))] + "TARGET_64BIT" + "pop{q}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "DI")]) + +(define_insn "popdi1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") + (mem:DI (reg:DI 7))) + (set (reg:DI 7) + (plus:DI (reg:DI 7) (const_int 8)))] + "TARGET_64BIT" + "pop{q}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "DI")]) + +(define_insn "*movdi_xor_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "const0_operand" "i")) + (clobber (reg:CC 17))] + "TARGET_64BIT && (!TARGET_USE_MOV0 || optimize_size) + && reload_completed" + "xor{l}\t{%k0, %k0|%k0, %k0}" + [(set_attr "type" "alu1") + (set_attr "mode" "SI") + (set_attr "length_immediate" "0")]) + +(define_insn "*movdi_or_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "const_int_operand" "i")) + (clobber (reg:CC 17))] + "TARGET_64BIT && (TARGET_PENTIUM || optimize_size) + && reload_completed + && GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) == -1" { - if (STACK_REG_P (operands[1])) - { - rtx xops[3]; - - if (! STACK_TOP_P (operands[1])) - abort (); + operands[1] = constm1_rtx; + return "or{q}\t{%1, %0|%0, %1}"; +} + [(set_attr "type" "alu1") + (set_attr "mode" "DI") + (set_attr "length_immediate" "1")]) + +(define_insn "*movdi_2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!m*y,!*y,!m,*Y,!*Y") + (match_operand:DI 1 "general_operand" "riFo,riF,*y,m,*Y,*Y,m"))] + "!TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + # + # + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + movdqa\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1}" + [(set_attr "type" "*,*,mmx,mmx,sse,sse,sse") + (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI")]) - xops[0] = AT_SP (SFmode); - xops[1] = GEN_INT (4); - xops[2] = stack_pointer_rtx; +(define_split + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && (! MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") - output_asm_insn (AS2 (sub%L2,%1,%2), xops); +;; %%% This multiword shite has got to go. +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && (!MMX_REG_P (operands[0]) && !SSE_REG_P (operands[0])) + && (!MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") - if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) - output_asm_insn (AS1 (fstp%S0,%0), xops); +(define_insn "*movdi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,mr,!mr,!m*y,!*y,!*Y,!m,!*Y") + (match_operand:DI 1 "general_operand" "Z,rem,i,re,n,*y,m,*Y,*Y,*m"))] + "TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (get_attr_type (insn)) + { + case TYPE_SSE: + if (register_operand (operands[0], DImode) + && register_operand (operands[1], DImode)) + return "movdqa\t{%1, %0|%0, %1}"; + /* FALLTHRU */ + case TYPE_MMX: + return "movq\t{%1, %0|%0, %1}"; + case TYPE_MULTI: + return "#"; + case TYPE_LEA: + return "lea{q}\t{%a1, %0|%0, %a1}"; + default: + if (flag_pic && SYMBOLIC_CONST (operands[1])) + abort (); + if (get_attr_mode (insn) == MODE_SI) + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else if (which_alternative == 2) + return "movabs{q}\t{%1, %0|%0, %1}"; else - output_asm_insn (AS1 (fst%S0,%0), xops); - - RET; + return "mov{q}\t{%1, %0|%0, %1}"; } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "5,6") + (const_string "mmx") + (eq_attr "alternative" "7,8") + (const_string "sse") + (eq_attr "alternative" "4") + (const_string "multi") + (and (ne (symbol_ref "flag_pic") (const_int 0)) + (match_operand:DI 1 "symbolic_operand" "")) + (const_string "lea") + ] + (const_string "imov"))) + (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*") + (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*") + (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,TI,DI")]) + +;; Stores and loads of ax to arbitary constant address. +;; We fake an second form of instruction to force reload to load address +;; into register when rax is not available +(define_insn "*movabsdi_1_rex64" + [(set (mem:DI (match_operand:DI 0 "x86_64_movabs_operand" "i,r,r")) + (match_operand:DI 1 "nonmemory_operand" "a,er,i"))] + "TARGET_64BIT" + "@ + movabs{q}\t{%1, %P0|%P0, %1} + mov{q}\t{%1, %a0|%a0, %1} + movabs{q}\t{%1, %a0|%a0, %1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*,*") + (set_attr "length_address" "8,0,0") + (set_attr "length_immediate" "0,*,*") + (set_attr "memory" "store") + (set_attr "mode" "DI")]) + +(define_insn "*movabsdi_2_rex64" + [(set (match_operand:DI 0 "register_operand" "=a,r") + (mem:DI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] + "TARGET_64BIT" + "@ + movabs{q}\t{%P1, %0|%0, %P1} + mov{q}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0") + (set_attr "memory" "load") + (set_attr "mode" "DI")]) + +;; Convert impossible stores of immediate to existing instructions. +;; First try to get scratch register and go through it. In case this +;; fails, move by 32bit parts. +(define_peephole2 + [(match_scratch:DI 2 "r") + (set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") - return AS1 (push%L0,%1); -}") +;; We need to define this as both peepholer and splitter for case +;; peephole2 pass is not run. +(define_peephole2 + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode) && 1" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "split_di (operands, 2, operands + 2, operands + 4);") (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))] - "") + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && (flow2_completed || (reload_completed && !flag_peephole2)) + && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "split_di (operands, 2, operands + 2, operands + 4);") + +(define_insn "*swapdi_rex64" + [(set (match_operand:DI 0 "register_operand" "+r") + (match_operand:DI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "TARGET_64BIT" + "xchg{q}\t%1, %0" + [(set_attr "type" "imov") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "mode" "DI") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) + (define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") + [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] "" - " + "ix86_expand_move (SFmode, operands); DONE;") + +(define_insn "*pushsf" + [(set (match_operand:SF 0 "push_operand" "=<,<,<") + (match_operand:SF 1 "general_no_elim_operand" "f#rx,rFm#fx,x#rf"))] + "!TARGET_64BIT" { - /* 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) + switch (which_alternative) { - operands[1] = force_reg (SFmode, operands[1]); - } + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (SFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (4); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - /* 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])); - } -}") + case 1: + return "push{l}\t%1"; + case 2: + return "#"; -;; 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)" - "* + default: + abort (); + } +} + [(set_attr "type" "multi,push,multi") + (set_attr "mode" "SF,SI,SF")]) + +(define_insn "*pushsf_rex64" + [(set (match_operand:SF 0 "push_operand" "=X,X,X") + (match_operand:SF 1 "nonmemory_no_elim_operand" "f#rx,rF#fx,x#rf"))] + "TARGET_64BIT" { - 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])) + switch (which_alternative) { - if (stack_top_dies) - return AS1 (fstp,%y0); + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (SFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (8); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{q}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; else - return AS1 (fld,%y0); - } + return "sub{q}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - /* Handle other kinds of writes from the 387 */ + case 1: + return "push{q}\t%q1"; - if (STACK_TOP_P (operands[1])) - { - if (stack_top_dies) - return AS1 (fstp%z0,%y0); - else - return AS1 (fst%z0,%y0); + case 2: + return "#"; + + default: + abort (); } +} + [(set_attr "type" "multi,push,multi") + (set_attr "mode" "SF,DI,SF")]) - /* Handle other kinds of reads to the 387 */ +(define_split + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "memory_operand" ""))] + "reload_completed + && GET_CODE (operands[1]) == MEM + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))" + [(set (match_dup 0) + (match_dup 1))] + "operands[1] = get_pool_constant (XEXP (operands[1], 0));") - 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); +;; %%% Kill this when call knows how to work this out. +(define_split + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "register_operand" ""))] + "!TARGET_64BIT && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (set (mem:SF (reg:SI 7)) (match_dup 1))]) - /* Handle all SFmode moves not involving the 387 */ +(define_split + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "register_operand" ""))] + "TARGET_64BIT && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:SF (reg:DI 7)) (match_dup 1))]) + +(define_insn "*movsf_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#xr,m,f#xr,r#xf,m,x#rf,x#rf,x#rf,m") + (match_operand:SF 1 "general_operand" "fm#rx,f#rx,G,rmF#fx,Fr#fx,H,x,xm#rf,x#rf"))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (reload_in_progress || reload_completed + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], SFmode))" +{ + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; + + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; - return singlemove_string (operands); -}" - [(set_attr "type" "fld")]) + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + abort(); + + case 3: + case 4: + return "mov{l}\t{%1, %0|%0, %1}"; + case 5: + return "pxor\t%0, %0"; + case 6: + if (TARGET_PARTIAL_REG_DEPENDENCY) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movss\t{%1, %0|%0, %1}"; + case 7: + case 8: + return "movss\t{%1, %0|%0, %1}"; + default: + abort(); + } +} + [(set_attr "type" "fmov,fmov,fmov,imov,imov,sse,sse,sse,sse") + (set_attr "mode" "SF,SF,SF,SI,SI,TI,SF,SF,SF")]) -(define_insn "swapsf" - [(set (match_operand:SF 0 "register_operand" "f") - (match_operand:SF 1 "register_operand" "f")) +(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))] - "" - "* + "reload_completed || !TARGET_SSE" { if (STACK_TOP_P (operands[0])) - return AS1 (fxch,%1); + return "fxch\t%1"; else - return AS1 (fxch,%0); -}") + return "fxch\t%0"; +} + [(set_attr "type" "fxch") + (set_attr "mode" "SF")]) +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + "ix86_expand_move (DFmode, operands); DONE;") -(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" - "* +;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. +;; Size of pushdf using integer insturctions is 2+2*memory operand size +;; On the average, pushdf using integers can be still shorter. Allow this +;; pattern for optimize_size too. + +(define_insn "*pushdf_nointeger" + [(set (match_operand:DF 0 "push_operand" "=<,<,<,<") + (match_operand:DF 1 "general_no_elim_operand" "f#Y,Fo#fY,*r#fY,Y#f"))] + "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES" { - if (STACK_REG_P (operands[1])) + switch (which_alternative) { - rtx xops[3]; - - xops[0] = AT_SP (DFmode); - xops[1] = GEN_INT (8); - xops[2] = stack_pointer_rtx; + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (DFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (8); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - output_asm_insn (AS2 (sub%L2,%1,%2), xops); + case 1: + case 2: + case 3: + return "#"; - if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) - output_asm_insn (AS1 (fstp%Q0,%0), xops); + default: + abort (); + } +} + [(set_attr "type" "multi") + (set_attr "mode" "DF,SI,SI,DF")]) + +(define_insn "*pushdf_integer" + [(set (match_operand:DF 0 "push_operand" "=<,<,<") + (match_operand:DF 1 "general_no_elim_operand" "f#rY,rFo#fY,Y#rf"))] + "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES" +{ + switch (which_alternative) + { + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (DFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (8); + if (TARGET_64BIT) + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{q}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{q}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; else - output_asm_insn (AS1 (fst%Q0,%0), xops); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - RET; - } - if (which_alternative == 1) - return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0); + case 1: + case 2: + return "#"; - return output_move_double (operands); -}") + default: + abort (); + } +} + [(set_attr "type" "multi") + (set_attr "mode" "DF,SI,DF")]) +;; %%% Kill this when call knows how to work this out. (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))] + (match_operand:DF 1 "register_operand" ""))] + "!TARGET_64BIT && reload_completed && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus: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" "") +(define_split + [(set (match_operand:DF 0 "push_operand" "") + (match_operand:DF 1 "register_operand" ""))] + "TARGET_64BIT && reload_completed && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:DF (reg:DI 7)) (match_dup 1))] + "") + +(define_split + [(set (match_operand:DF 0 "push_operand" "") (match_operand:DF 1 "general_operand" ""))] - "" - " + "reload_completed" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +;; Moving is usually shorter when only FP registers are used. This separate +;; movdf pattern avoids the use of integer registers for FP operations +;; when optimizing for size. + +(define_insn "*movdf_nointeger" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,m,f#Y,*r,o,Y#f,Y#f,Y#f,m") + (match_operand:DF 1 "general_operand" "fm#Y,f#Y,G,*roF,F*r,H,Y#f,YHm#f,Y#f"))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (optimize_size || !TARGET_INTEGER_DFMODE_MOVES) + && (reload_in_progress || reload_completed + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], DFmode))" { - /* 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])) + switch (which_alternative) { - 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)' */ + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; - if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) - { - if (stack_top_dies) - return AS1 (fstp,%y0); + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; else - return AS1 (fld,%y0); - } + return "fst%z0\t%y0"; - /* Handle other kinds of writes from the 387 */ + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + abort(); + + case 3: + case 4: + return "#"; + case 5: + return "pxor\t%0, %0"; + case 6: + if (TARGET_PARTIAL_REG_DEPENDENCY) + return "movapd\t{%1, %0|%0, %1}"; + else + return "movsd\t{%1, %0|%0, %1}"; + case 7: + case 8: + return "movsd\t{%1, %0|%0, %1}"; - if (STACK_TOP_P (operands[1])) + default: + abort(); + } +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi,sse,sse,sse,sse") + (set_attr "mode" "DF,DF,DF,SI,SI,TI,DF,DF,DF")]) + +(define_insn "*movdf_integer" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Yr,m,f#Yr,r#Yf,o,Y#rf,Y#rf,Y#rf,m") + (match_operand:DF 1 "general_operand" "fm#Yr,f#Yr,G,roF#Yf,Fr#Yf,H,Y#rf,Ym#rf,Y#rf"))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && !optimize_size && TARGET_INTEGER_DFMODE_MOVES + && (reload_in_progress || reload_completed + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], DFmode))" +{ + switch (which_alternative) { - if (stack_top_dies) - return AS1 (fstp%z0,%y0); + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; else - return AS1 (fst%z0,%y0); - } + return "fst\t%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); + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; - if (STACK_TOP_P (operands[0])) - return AS1 (fld%z1,%y1); + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + abort(); - /* Handle all DFmode moves not involving the 387 */ + case 3: + case 4: + return "#"; - return output_move_double (operands); -}" - [(set_attr "type" "fld")]) + case 5: + return "pxor\t%0, %0"; + case 6: + if (TARGET_PARTIAL_REG_DEPENDENCY) + return "movapd\t{%1, %0|%0, %1}"; + else + return "movsd\t{%1, %0|%0, %1}"; + case 7: + case 8: + return "movsd\t{%1, %0|%0, %1}"; + default: + abort(); + } +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi,sse,sse,sse,sse") + (set_attr "mode" "DF,DF,DF,SI,SI,TI,DF,DF,DF")]) +(define_split + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "reload_completed + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && ! (ANY_FP_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[0])))) + && ! (ANY_FP_REG_P (operands[1]) || + (GET_CODE (operands[1]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") -(define_insn "swapdf" - [(set (match_operand:DF 0 "register_operand" "f") - (match_operand:DF 1 "register_operand" "f")) +(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))] - "" - "* + "reload_completed || !TARGET_SSE2" { if (STACK_TOP_P (operands[0])) - return AS1 (fxch,%1); + return "fxch\t%1"; else - return AS1 (fxch,%0); -}") + return "fxch\t%0"; +} + [(set_attr "type" "fxch") + (set_attr "mode" "DF")]) -(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" - "* +(define_expand "movxf" + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "!TARGET_64BIT" + "ix86_expand_move (XFmode, operands); DONE;") + +(define_expand "movtf" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "" + "ix86_expand_move (TFmode, operands); DONE;") + +;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. +;; Size of pushdf using integer insturctions is 3+3*memory operand size +;; Pushing using integer instructions is longer except for constants +;; and direct memory references. +;; (assuming that any given constant is pushed only once, but this ought to be +;; handled elsewhere). + +(define_insn "*pushxf_nointeger" + [(set (match_operand:XF 0 "push_operand" "=X,X,X") + (match_operand:XF 1 "general_no_elim_operand" "f,Fo,*r"))] + "!TARGET_64BIT && optimize_size" { - if (STACK_REG_P (operands[1])) + switch (which_alternative) { - rtx xops[3]; + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (12); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - xops[0] = AT_SP (XFmode); - xops[1] = GEN_INT (12); - xops[2] = stack_pointer_rtx; + case 1: + case 2: + return "#"; - output_asm_insn (AS2 (sub%L2,%1,%2), xops); + default: + abort (); + } +} + [(set_attr "type" "multi") + (set_attr "mode" "XF,SI,SI")]) + +(define_insn "*pushtf_nointeger" + [(set (match_operand:TF 0 "push_operand" "=<,<,<") + (match_operand:TF 1 "general_no_elim_operand" "f,Fo,*r"))] + "optimize_size" +{ + switch (which_alternative) + { + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (16); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - 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); + case 1: + case 2: + return "#"; - RET; + default: + abort (); } +} + [(set_attr "type" "multi") + (set_attr "mode" "XF,SI,SI")]) - if (which_alternative == 1) - return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0); +(define_insn "*pushxf_integer" + [(set (match_operand:XF 0 "push_operand" "=<,<") + (match_operand:XF 1 "general_no_elim_operand" "f#r,ro#f"))] + "!TARGET_64BIT && !optimize_size" +{ + switch (which_alternative) + { + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (12); + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; + + case 1: + return "#"; + + default: + abort (); + } +} + [(set_attr "type" "multi") + (set_attr "mode" "XF,SI")]) + +(define_insn "*pushtf_integer" + [(set (match_operand:TF 0 "push_operand" "=<,<") + (match_operand:TF 1 "general_no_elim_operand" "f#r,rFo#f"))] + "!optimize_size" +{ + switch (which_alternative) + { + case 0: + /* %%% We loose REG_DEAD notes for controling pops if we split late. */ + operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx); + operands[2] = stack_pointer_rtx; + operands[3] = GEN_INT (16); + if (TARGET_64BIT) + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{q}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{q}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; + else + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "sub{l}\t{%3, %2|%2, %3}\;fstp%z0\t%y0"; + else + return "sub{l}\t{%3, %2|%2, %3}\;fst%z0\t%y0"; - return output_move_double (operands); - }") + case 1: + return "#"; + + default: + abort (); + } +} + [(set_attr "type" "multi") + (set_attr "mode" "XF,SI")]) + +(define_split + [(set (match_operand 0 "push_operand" "") + (match_operand 1 "general_operand" ""))] + "reload_completed + && (GET_MODE (operands[0]) == XFmode + || GET_MODE (operands[0]) == TFmode + || GET_MODE (operands[0]) == DFmode) + && (!REG_P (operands[1]) || !ANY_FP_REGNO_P (REGNO (operands[1])))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") (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))] - "") + (match_operand:XF 1 "register_operand" ""))] + "!TARGET_64BIT && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus: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" ""))] - "" - " +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (match_operand:TF 1 "register_operand" ""))] + "!TARGET_64BIT && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:TF (reg:SI 7)) (match_dup 1))]) + +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (match_operand:TF 1 "register_operand" ""))] + "TARGET_64BIT && ANY_FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (set (mem:TF (reg:DI 7)) (match_dup 1))]) + +;; Do not use integer registers when optimizing for size +(define_insn "*movxf_nointeger" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o") + (match_operand:XF 1 "general_operand" "fm,f,G,*roF,F*r"))] + "!TARGET_64BIT + && optimize_size + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (reload_in_progress || reload_completed + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], XFmode))" { - /* 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) + switch (which_alternative) { - operands[1] = force_reg (XFmode, operands[1]); - } + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; - /* 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])); - } -}") + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\;fld%z0\t%y0"; + else + return "fstp%z0\t%y0"; + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + break; -(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)" - "* + case 3: case 4: + return "#"; + } + abort(); +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) + +(define_insn "*movtf_nointeger" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m,f,*r,o") + (match_operand:TF 1 "general_operand" "fm,f,G,*roF,F*r"))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && optimize_size + && (reload_in_progress || reload_completed + || GET_CODE (operands[1]) != CONST_DOUBLE + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || memory_operand (operands[0], TFmode))" { - int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; - /* First handle a `pop' insn or a `fld %st(0)' */ + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\;fld%z0\t%y0"; + else + return "fstp%z0\t%y0"; + + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + break; - if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) + case 3: case 4: + return "#"; + } + abort(); +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) + +(define_insn "*movxf_integer" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o") + (match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))] + "!TARGET_64BIT + && !optimize_size + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (reload_in_progress || reload_completed + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], XFmode))" +{ + switch (which_alternative) { - if (stack_top_dies) - return AS1 (fstp,%y0); + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; else - return AS1 (fld,%y0); - } + return "fst\t%y0"; - /* Handle other kinds of writes from the 387 */ + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\;fld%z0\t%y0"; + else + return "fstp%z0\t%y0"; - if (STACK_TOP_P (operands[1])) - { - output_asm_insn (AS1 (fstp%z0,%y0), operands); - if (! stack_top_dies) - return AS1 (fld%z0,%y0); + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + break; - RET; + case 3: case 4: + return "#"; } + abort(); +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) + +(define_insn "*movtf_integer" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o") + (match_operand:TF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))] + "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && !optimize_size + && (reload_in_progress || reload_completed + || GET_CODE (operands[1]) != CONST_DOUBLE + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || memory_operand (operands[0], TFmode))" +{ + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; - /* Handle other kinds of reads to the 387 */ + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\;fld%z0\t%y0"; + else + return "fstp%z0\t%y0"; - if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) - return output_move_const_single (operands); + case 2: + switch (standard_80387_constant_p (operands[1])) + { + case 1: + return "fldz"; + case 2: + return "fld1"; + } + break; - if (STACK_TOP_P (operands[0])) - return AS1 (fld%z1,%y1); + case 3: case 4: + return "#"; + } + abort(); +} + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) - /* Handle all XFmode moves not involving the 387 */ +(define_split + [(set (match_operand 0 "nonimmediate_operand" "") + (match_operand 1 "general_operand" ""))] + "reload_completed + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + && (GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == TFmode) + && ! (ANY_FP_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[0])))) + && ! (ANY_FP_REG_P (operands[1]) || + (GET_CODE (operands[1]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") - return output_move_double (operands); -}") +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operand 1 "memory_operand" ""))] + "reload_completed + && GET_CODE (operands[1]) == MEM + && (GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == TFmode + || GET_MODE (operands[0]) == SFmode || GET_MODE (operands[0]) == DFmode) + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0)) + && (!(SSE_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && SSE_REG_P (SUBREG_REG (operands[0])))) + || standard_sse_constant_p (get_pool_constant (XEXP (operands[1], 0)))) + && (!(FP_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && FP_REG_P (SUBREG_REG (operands[0])))) + || standard_80387_constant_p (get_pool_constant (XEXP (operands[1], 0))))" + [(set (match_dup 0) + (match_dup 1))] + "operands[1] = get_pool_constant (XEXP (operands[1], 0));") -(define_insn "swapxf" - [(set (match_operand:XF 0 "register_operand" "f") - (match_operand:XF 1 "register_operand" "f")) +(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); + return "fxch\t%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" ""))] + return "fxch\t%0"; +} + [(set_attr "type" "fxch") + (set_attr "mode" "XF")]) + +(define_insn "swaptf" + [(set (match_operand:TF 0 "register_operand" "+f") + (match_operand:TF 1 "register_operand" "+f")) + (set (match_dup 1) + (match_dup 0))] "" - " { - /* 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; - } -}") + if (STACK_TOP_P (operands[0])) + return "fxch\t%1"; + else + return "fxch\t%0"; +} + [(set_attr "type" "fxch") + (set_attr "mode" "XF")]) -;;- conversion instructions -;;- NONE - -;;- zero extension instructions -;; See comments by `andsi' for when andl is faster than movzx. +;; Zero extension instructions (define_expand "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_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) +{ + if (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size) { - 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; + operands[1] = force_reg (HImode, operands[1]); + emit_insn (gen_zero_extendhisi2_and (operands[0], operands[1])); + DONE; } +}) -#ifdef INTEL_SYNTAX - return AS2 (movzx,%1,%0); -#else - return AS2 (movz%W0%L0,%1,%0); -#endif -}") +(define_insn "zero_extendhisi2_and" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))) + (clobber (reg:CC 17))] + "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "SI")]) (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]));") - + (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) + (clobber (reg:CC 17))])] + "") -(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_insn "*zero_extendhisi2_movzwl" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size" + "movz{wl|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) (define_expand "zero_extendqihi2" - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + [(parallel + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "" "") -(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 "*zero_extendqihi2_and" + [(set (match_operand:HI 0 "register_operand" "=r,?&q") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) + (clobber (reg:CC 17))] + "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "HI")]) -(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]; +(define_insn "*zero_extendqihi2_movzbw_and" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) + (clobber (reg:CC 17))] + "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size" + "#" + [(set_attr "type" "imovx,alu1") + (set_attr "mode" "HI")]) - 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_insn "*zero_extendqihi2_movzbw" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && reload_completed" + "movz{bw|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "HI")]) +;; For the movzbw case strip only the clobber (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]));") - + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) + && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]) +;; When source and destination does not overlap, clear destination +;; first and then do the movb (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]));") - + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ANY_QI_REG_P (operands[0]) + && (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size) + && !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_lowpart (QImode, operands[0]);") + +;; Rest is handled by single and. (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]));") + (zero_extend:HI (match_operand:QI 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) == true_regnum (operands[1])" + [(parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255))) + (clobber (reg:CC 17))])] + "") (define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "" "") -(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; - } +(define_insn "*zero_extendqisi2_and" + [(set (match_operand:SI 0 "register_operand" "=r,?&q") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) + (clobber (reg:CC 17))] + "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "SI")]) - 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; - } +(define_insn "*zero_extendqisi2_movzbw_and" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) + (clobber (reg:CC 17))] + "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size" + "#" + [(set_attr "type" "imovx,alu1") + (set_attr "mode" "SI")]) -#ifdef INTEL_SYNTAX - return AS2 (movzx,%1,%0); -#else - return AS2 (movz%B0%L0,%1,%0); -#endif -}") +(define_insn "*zero_extendqisi2_movzbw" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && reload_completed" + "movz{bl|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) +;; For the movzbl case strip only the clobber (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]));") - + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) + && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" + [(set (match_dup 0) + (zero_extend:SI (match_dup 1)))]) +;; When source and destination does not overlap, clear destination +;; first and then do the movb (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]));") - + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && ANY_QI_REG_P (operands[0]) + && (ANY_QI_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM) + && (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size) + && !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_lowpart (QImode, operands[0]);") + +;; Rest is handled by single and. (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")))] + (zero_extend:SI (match_operand:QI 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) == true_regnum (operands[1])" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255))) + (clobber (reg:CC 17))])] + "") + +;; %%% Kill me once multi-word ops are sane. +(define_expand "zero_extendsidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))] "" - "#") + "if (!TARGET_64BIT) + { + emit_insn (gen_zero_extendsidi2_32 (operands[0], operands[1])); + DONE; + } + ") + +(define_insn "zero_extendsidi2_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,rm,r"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "#" + [(set_attr "mode" "SI")]) + +(define_insn "zero_extendsidi2_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm,0")))] + "TARGET_64BIT" + "@ + mov\t{%k1, %k0|%k0, %k1} + #" + [(set_attr "type" "imovx,imov") + (set_attr "mode" "SI,DI")]) + +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (zero_extend:DI (match_dup 0)))] + "TARGET_64BIT" + [(set (match_dup 4) (const_int 0))] + "split_di (&operands[0], 1, &operands[3], &operands[4]);") (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])" + (zero_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && 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" + (zero_extend:DI (match_operand:SI 1 "general_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && 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]);") + +(define_insn "zero_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_64BIT" + "@ + movz{wl|x}\t{%1, %k0|%k0, %1} + movz{wq|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI,DI")]) + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "Q,m")))] + "TARGET_64BIT" + "@ + movz{bl|x}\t{%1, %k0|%k0, %1} + movz{bq|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI,DI")]) -;;- sign extension instructions +;; 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"))] +(define_expand "extendsidi2" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (reg:CC 17)) + (clobber (match_scratch:SI 2 ""))])] "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_extendsidi2_rex64 (operands[0], operands[1])); + DONE; + } +}) + +(define_insn "*extendsidi2_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=*A,r,?r,?*o") + (sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,r"))) + (clobber (reg:CC 17)) + (clobber (match_scratch:SI 2 "=X,X,X,&r"))] + "!TARGET_64BIT" "#") +(define_insn "extendsidi2_rex64" + [(set (match_operand:DI 0 "register_operand" "=*a,r") + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "*0,rm")))] + "TARGET_64BIT" + "@ + {cltq|cdqe} + movs{lq|x}\t{%1,%0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "DI") + (set_attr "prefix_0f" "0") + (set_attr "modrm" "0,1")]) + +(define_insn "extendhidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "TARGET_64BIT" + "movs{wq|x}\t{%1,%0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "DI")]) + +(define_insn "extendqidi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "TARGET_64BIT" + "movs{bq|x}\t{%1,%0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "DI")]) + ;; 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 (reg:CC 17)) (clobber (match_operand:SI 2 "register_operand" ""))] - "(flow2_completed + "(reload_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))) + (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31))) + (clobber (reg:CC 17))]) (set (match_dup 4) (match_dup 1))] "split_di (&operands[0], 1, &operands[3], &operands[4]);") @@ -2063,10 +3783,10 @@ (define_split [(set (match_operand:DI 0 "memory_operand" "") (sign_extend:DI (match_operand:SI 1 "register_operand" ""))) + (clobber (reg:CC 17)) (clobber (match_operand:SI 2 "register_operand" ""))] - "flow2_completed" + "reload_completed" [(const_int 0)] - " { split_di (&operands[0], 1, &operands[3], &operands[4]); @@ -2075,28 +3795,28 @@ /* 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)) + && (optimize_size || TARGET_USE_CLTD)) { - emit_insn (gen_ashrsi3_31 (operands[2], operands[1])); + emit_insn (gen_ashrsi3_31 (operands[2], operands[1], GEN_INT (31))); } else { emit_move_insn (operands[2], operands[1]); - emit_insn (gen_ashrsi3_31 (operands[2], operands[2])); + emit_insn (gen_ashrsi3_31 (operands[2], operands[2], GEN_INT (31))); } 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 (reg:CC 17)) (clobber (match_scratch:SI 2 ""))] "reload_completed" [(const_int 0)] - " { split_di (&operands[0], 1, &operands[3], &operands[4]); @@ -2105,1600 +3825,3052 @@ /* Generate a cltd if possible and doing so it profitable. */ if (true_regnum (operands[3]) == 0 - && (optimize_size || !TARGET_PENTIUM)) + && (optimize_size || TARGET_USE_CLTD)) { - emit_insn (gen_ashrsi3_31 (operands[4], operands[3])); + emit_insn (gen_ashrsi3_31 (operands[4], operands[3], GEN_INT (31))); 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])); + emit_insn (gen_ashrsi3_31 (operands[4], operands[4], GEN_INT (31))); 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")))] + [(set (match_operand:SI 0 "register_operand" "=*a,r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "*0,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 -}") + switch (get_attr_prefix_0f (insn)) + { + case 0: + return "{cwtl|cwde}"; + default: + return "movs{wl|x}\t{%1,%0|%0, %1}"; + } +} + [(set_attr "type" "imovx") + (set_attr "mode" "SI") + (set (attr "prefix_0f") + ;; movsx is short decodable while cwtl is vector decoded. + (if_then_else (and (eq_attr "cpu" "!k6") + (eq_attr "alternative" "0")) + (const_string "0") + (const_string "1"))) + (set (attr "modrm") + (if_then_else (eq_attr "prefix_0f" "0") + (const_string "0") + (const_string "1")))]) + +(define_insn "*extendhisi2_zext" + [(set (match_operand:DI 0 "register_operand" "=*a,r") + (zero_extend:DI + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "*0,rm"))))] + "TARGET_64BIT" +{ + switch (get_attr_prefix_0f (insn)) + { + case 0: + return "{cwtl|cwde}"; + default: + return "movs{wl|x}\t{%1,%k0|%k0, %1}"; + } +} + [(set_attr "type" "imovx") + (set_attr "mode" "SI") + (set (attr "prefix_0f") + ;; movsx is short decodable while cwtl is vector decoded. + (if_then_else (and (eq_attr "cpu" "!k6") + (eq_attr "alternative" "0")) + (const_string "0") + (const_string "1"))) + (set (attr "modrm") + (if_then_else (eq_attr "prefix_0f" "0") + (const_string "0") + (const_string "1")))]) (define_insn "extendqihi2" - [(set (match_operand:HI 0 "register_operand" "=r") - (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + [(set (match_operand:HI 0 "register_operand" "=*a,r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "*0,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 -}") + switch (get_attr_prefix_0f (insn)) + { + case 0: + return "{cbtw|cbw}"; + default: + return "movs{bw|x}\t{%1,%0|%0, %1}"; + } +} + [(set_attr "type" "imovx") + (set_attr "mode" "HI") + (set (attr "prefix_0f") + ;; movsx is short decodable while cwtl is vector decoded. + (if_then_else (and (eq_attr "cpu" "!k6") + (eq_attr "alternative" "0")) + (const_string "0") + (const_string "1"))) + (set (attr "modrm") + (if_then_else (eq_attr "prefix_0f" "0") + (const_string "0") + (const_string "1")))]) (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 -}") - + "movs{bl|x}\t{%1,%0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) + +(define_insn "*extendqisi2_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))))] + "TARGET_64BIT" + "movs{bl|x}\t{%1,%k0|%k0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) -;; Truncation of long long -> 32 bit +;; Conversions between float and double. -(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; - } -}") +;; These are all no-ops in the model used for the 80387. So just +;; emit moves. -(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]; +;; %%% Kill these when call knows how to work out a DFmode push earlier. +(define_insn "*dummy_extendsfdf2" + [(set (match_operand:DF 0 "push_operand" "=<") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fY")))] + "0" + "#") - 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); +(define_split + [(set (match_operand:DF 0 "push_operand" "") + (float_extend:DF (match_operand:SF 1 "register_operand" "")))] + "!TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:DF (reg:SI 7)) (float_extend:DF (match_dup 1)))]) - RET; -}") +(define_split + [(set (match_operand:DF 0 "push_operand" "") + (float_extend:DF (match_operand:SF 1 "register_operand" "")))] + "TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (set (mem:DF (reg:DI 7)) (float_extend:DF (match_dup 1)))]) + +(define_insn "*dummy_extendsfxf2" + [(set (match_operand:XF 0 "push_operand" "=<") + (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "f")))] + "0" + "#") -(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]; +(define_split + [(set (match_operand:XF 0 "push_operand" "") + (float_extend:XF (match_operand:SF 1 "register_operand" "")))] + "!TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12))) + (set (mem:XF (reg:SI 7)) (float_extend:XF (match_dup 1)))]) + +(define_insn "*dummy_extendsftf2" + [(set (match_operand:TF 0 "push_operand" "=<") + (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "f")))] + "0" + "#") - 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); +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (float_extend:TF (match_operand:SF 1 "register_operand" "")))] + "!TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:TF (reg:SI 7)) (float_extend:TF (match_dup 1)))]) - RET; -}") +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (float_extend:TF (match_operand:SF 1 "register_operand" "")))] + "TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (set (mem:DF (reg:DI 7)) (float_extend:TF (match_dup 1)))]) + +(define_insn "*dummy_extenddfxf2" + [(set (match_operand:XF 0 "push_operand" "=<") + (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "f")))] + "0" + "#") + +(define_split + [(set (match_operand:XF 0 "push_operand" "") + (float_extend:XF (match_operand:DF 1 "register_operand" "")))] + "!TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12))) + (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))]) + +(define_insn "*dummy_extenddftf2" + [(set (match_operand:TF 0 "push_operand" "=<") + (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "f")))] + "0" + "#") +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (float_extend:TF (match_operand:DF 1 "register_operand" "")))] + "!TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:TF (reg:SI 7)) (float_extend:XF (match_dup 1)))]) - -;; Conversions between float and double. +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (float_extend:TF (match_operand:DF 1 "register_operand" "")))] + "TARGET_64BIT && FP_REGNO_P (REGNO (operands[1]))" + [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (set (mem:TF (reg:DI 7)) (float_extend:TF (match_dup 1)))]) (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" - " + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))] + "TARGET_80387 || TARGET_SSE2" { 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)" - "* +(define_insn "*extendsfdf2_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,mf#Y,Y#f") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm#Y,f#Y,mY#f")))] + "(TARGET_80387 || TARGET_SSE2) + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { - output_float_extend (insn, operands); - return \"\"; -}" - [(set_attr "type" "fld,fpop,fld,fpop")]) + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; -(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)))] - "") + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; -(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))] - "") + else + return "fst%z0\t%y0"; + case 2: + return "cvtss2sd\t{%1, %0|%0, %1}"; -(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)))] - "") + default: + abort (); + } +} + [(set_attr "type" "fmov,fmov,sse") + (set_attr "mode" "SF,XF,DF")]) + +(define_insn "*extendsfdf2_1_sse_only" + [(set (match_operand:DF 0 "register_operand" "=Y") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "mY")))] + "!TARGET_80387 && TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "cvtss2sd\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) -(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)" - "* +(define_expand "extendsfxf2" + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))] + "!TARGET_64BIT && TARGET_80387" { - output_float_extend (insn, operands); - return \"\"; -}" - [(set_attr "type" "fld,fpop")]) + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (SFmode, operands[1]); +}) -(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))])] +(define_insn "*extendsfxf2_1" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m") + (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))] + "!TARGET_64BIT && TARGET_80387 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; + + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\n\tfld%z0\t%y0"; + else + return "fstp%z0\t%y0"; + + default: + abort (); + } +} + [(set_attr "type" "fmov") + (set_attr "mode" "SF,XF")]) + +(define_expand "extendsftf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))] "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); -}") + operands[1] = force_reg (SFmode, operands[1]); +}) -(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)" - "* +(define_insn "*extendsftf2_1" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m") + (float_extend:TF (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,fld,fpop")]) + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; -(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)))] - "") + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\n\tfld%z0\t%y0"; + else + return "fstp%z0\t%y0"; -(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))] - "") + default: + abort (); + } +} + [(set_attr "type" "fmov") + (set_attr "mode" "SF,XF")]) -(define_split +(define_expand "extenddfxf2" [(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)))] - "") + (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))] + "!TARGET_64BIT && TARGET_80387" +{ + if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) + operands[1] = force_reg (DFmode, operands[1]); +}) -(define_insn "" +(define_insn "*extenddfxf2_1" [(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)" - "* + (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))] + "!TARGET_64BIT && TARGET_80387 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" { - output_float_extend (insn, operands); - return \"\"; -}" - [(set_attr "type" "fld,fpop")]) + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; -(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))])] + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\n\tfld%z0\t%y0"; + else + return "fstp%z0\t%y0"; + + default: + abort (); + } +} + [(set_attr "type" "fmov") + (set_attr "mode" "DF,XF")]) + +(define_expand "extenddftf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))] "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); -}") + operands[1] = force_reg (DFmode, operands[1]); +}) -(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)" - "* +(define_insn "*extenddftf2_1" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m") + (float_extend:TF (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,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)))] - "") + switch (which_alternative) + { + case 0: + if (REG_P (operands[1]) + && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp\t%y0"; + else if (STACK_TOP_P (operands[0])) + return "fld%z1\t%y1"; + else + return "fst\t%y0"; -(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))] - "") + case 1: + /* There is no non-popping store to memory for XFmode. So if + we need one, follow the store with a load. */ + if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0\n\tfld%z0\t%y0"; + else + return "fstp%z0\t%y0"; -(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)))] - "") + default: + abort (); + } +} + [(set_attr "type" "fmov") + (set_attr "mode" "DF,XF")]) -(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")]) +;; %%% This seems bad bad news. +;; This cannot output into an f-reg because there is no way to be sure +;; of truncating in that case. Otherwise this is just like a simple move +;; insn. So we pretend we can output to a reg in order to get better +;; register preferencing, but we really use a stack slot. (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" + "TARGET_80387 || TARGET_SSE2" " + if (TARGET_80387) + operands[2] = assign_386_stack_local (SFmode, 0); + else + { + emit_insn (gen_truncdfsf2_sse_only (operands[0], operands[1])); + DONE; + } +") + +(define_insn "*truncdfsf2_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))] + "TARGET_80387 && !TARGET_SSE2" { - operands[2] = (rtx) assign_386_stack_local (SFmode, 0); -}") + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort (); + } +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "SF,SF,SF,SF")]) -(define_insn "" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r") +(define_insn "*truncdfsf2_1_sse" + [(set (match_operand:SF 0 "nonimmediate_operand" "=*!m,?f#rx,?r#fx,?x#rf,Y") (float_truncate:SF - (match_operand:DF 1 "register_operand" "0,f,f"))) - (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))] - "TARGET_80387" - "* + (match_operand:DF 1 "nonimmediate_operand" "f,f,f,f,mY"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m,X"))] + "TARGET_80387 && TARGET_SSE2" { - int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; - rtx xops[1]; + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + case 4: + return "cvtsd2ss\t{%1, %0|%0, %1}"; + default: + abort (); + } +} + [(set_attr "type" "fmov,multi,multi,multi,sse") + (set_attr "mode" "SF,SF,SF,SF,DF")]) - xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2]; +(define_insn "*truncdfsf2_2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=Y,!m") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "mY,f")))] + "TARGET_80387 && TARGET_SSE2 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" +{ + switch (which_alternative) + { + case 0: + return "cvtsd2ss\t{%1, %0|%0, %1}"; + case 1: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort (); + } +} + [(set_attr "type" "sse,fmov") + (set_attr "mode" "DF,SF")]) - if (stack_top_dies || STACK_REG_P (operands[0])) - output_asm_insn (AS1 (fstp%z0,%0), xops); +(define_insn "truncdfsf2_3" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF + (match_operand:DF 1 "register_operand" "f")))] + "TARGET_80387" +{ + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; 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 "fst%z0\t%y0"; +} + [(set_attr "type" "fmov") + (set_attr "mode" "SF")]) - return \"\"; -}" - [(set_attr "type" "fpop")]) +(define_insn "truncdfsf2_sse_only" + [(set (match_operand:SF 0 "register_operand" "=Y") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" "mY")))] + "!TARGET_80387 && TARGET_SSE2" + "cvtsd2ss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) (define_split - [(set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_operand:DF 1 "register_operand" ""))) + [(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 2) - (float_truncate:SF (match_dup 1))) - (set (match_dup 0) - (match_dup 2))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] "") (define_split - [(set (match_operand:SF 0 "memory_operand" "") - (float_truncate:SF (match_operand:DF 1 "register_operand" ""))) + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (float_truncate:SF + (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (match_operand 2 "" ""))] + "TARGET_80387 && reload_completed + && !FP_REG_P (operands[0]) && !FP_REG_P (operands[1])" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] + "") + +(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 0) - (float_truncate:SF (match_dup 1)))] + "TARGET_80387 && reload_completed + && FP_REG_P (operands[1])" + [(set (match_dup 2) (float_truncate:SF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] "") -;; This cannot output into an f-reg because there is no way to be sure -;; of truncating in that case. +(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_64BIT && TARGET_80387" + "operands[2] = assign_386_stack_local (SFmode, 0);") -(define_insn "" - [(set (match_operand:SF 0 "memory_operand" "=m") - (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))] - "TARGET_80387" - "* +(define_insn "*truncxfsf2_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf") + (float_truncate:SF + (match_operand:XF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))] + "!TARGET_64BIT && TARGET_80387" { - int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); + } +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "SF")]) - if (stack_top_dies) - return AS1 (fstp%z0,%0); +(define_insn "*truncxfsf2_2" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF + (match_operand:XF 1 "register_operand" "f")))] + "!TARGET_64BIT && TARGET_80387" +{ + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; else - return AS1 (fst%z0,%0); -}" - [(set_attr "type" "fpop")]) + return "fst%z0\t%y0"; +} + [(set_attr "type" "fmov") + (set_attr "mode" "SF")]) -(define_expand "truncxfsf2" +(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" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] + "") + +(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_expand "trunctfsf2" [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") (float_truncate:SF - (match_operand:XF 1 "register_operand" ""))) + (match_operand:TF 1 "register_operand" ""))) (clobber (match_dup 2))])] "TARGET_80387" - " -{ - operands[2] = (rtx) assign_386_stack_local (SFmode, 0); -}") + "operands[2] = assign_386_stack_local (SFmode, 0);") -(define_insn "" - [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r") +(define_insn "*trunctfsf2_1" + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf") (float_truncate:SF - (match_operand:XF 1 "register_operand" "0,f,f"))) - (clobber (match_operand:SF 2 "memory_operand" "m,m,m"))] + (match_operand:TF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:SF 2 "memory_operand" "=X,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]; + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); + } +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "SF")]) - if (stack_top_dies || STACK_REG_P (operands[0])) - output_asm_insn (AS1 (fstp%z0,%0), xops); +(define_insn "*trunctfsf2_2" + [(set (match_operand:SF 0 "memory_operand" "=m") + (float_truncate:SF + (match_operand:TF 1 "register_operand" "f")))] + "TARGET_80387" +{ + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; 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")]) + return "fst%z0\t%y0"; +} + [(set_attr "type" "fmov") + (set_attr "mode" "SF")]) (define_split - [(set (match_operand:SF 0 "register_operand" "") - (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) + [(set (match_operand:SF 0 "memory_operand" "") + (float_truncate:SF + (match_operand:TF 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))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:SF (match_dup 1)))] "") (define_split - [(set (match_operand:SF 0 "memory_operand" "") - (float_truncate:SF (match_operand:XF 1 "register_operand" ""))) + [(set (match_operand:SF 0 "register_operand" "") + (float_truncate:SF + (match_operand:TF 1 "register_operand" ""))) (clobber (match_operand:SF 2 "memory_operand" ""))] "TARGET_80387 && reload_completed" - [(set (match_dup 0) - (float_truncate:SF (match_dup 1)))] + [(set (match_dup 2) (float_truncate:SF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] "") -(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); -}") + "!TARGET_64BIT && TARGET_80387" + "operands[2] = assign_386_stack_local (DFmode, 0);") -(define_insn "" - [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r") +(define_insn "*truncxfdf2_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#rY,?r#fY,?Y#rf") (float_truncate:DF - (match_operand:XF 1 "register_operand" "0,f,f"))) - (clobber (match_operand:DF 2 "memory_operand" "m,m,o"))] - "TARGET_80387" - "* + (match_operand:XF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))] + "!TARGET_64BIT && 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])) + switch (which_alternative) { - xops[0] = operands[0]; - xops[1] = operands[2]; - output_asm_insn (output_move_double (xops), xops); + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); } + abort (); +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "DF")]) - return \"\"; -}" - [(set_attr "type" "fpop")]) +(define_insn "*truncxfdf2_2" + [(set (match_operand:DF 0 "memory_operand" "=m") + (float_truncate:DF + (match_operand:XF 1 "register_operand" "f")))] + "!TARGET_64BIT && TARGET_80387" +{ + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; +} + [(set_attr "type" "fmov") + (set_attr "mode" "DF")]) (define_split - [(set (match_operand:DF 0 "register_operand" "") - (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) + [(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 2) - (float_truncate:DF (match_dup 1))) - (set (match_dup 0) - (match_dup 2))] + "TARGET_80387" + [(set (match_dup 0) (float_truncate:DF (match_dup 1)))] "") (define_split - [(set (match_operand:DF 0 "memory_operand" "") - (float_truncate:DF (match_operand:XF 1 "register_operand" ""))) + [(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 0) - (float_truncate:DF (match_dup 1)))] + [(set (match_dup 2) (float_truncate:DF (match_dup 1))) + (set (match_dup 0) (match_dup 2))] "") -(define_insn "" - [(set (match_operand:DF 0 "memory_operand" "=m") - (float_truncate:DF (match_operand:XF 1 "register_operand" "f")))] +(define_expand "trunctfdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (float_truncate:DF + (match_operand:TF 1 "register_operand" ""))) + (clobber (match_dup 2))])] "TARGET_80387" - "* -{ - int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + "operands[2] = assign_386_stack_local (DFmode, 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 ""))])] +(define_insn "*trunctfdf2_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#rY,?r#fY,?Y#rf") + (float_truncate:DF + (match_operand:TF 1 "register_operand" "f,f,f,f"))) + (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))] "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")]) + switch (which_alternative) + { + case 0: + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; + default: + abort(); + } + abort (); +} + [(set_attr "type" "fmov,multi,multi,multi") + (set_attr "mode" "DF")]) -(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 ""))])] + (define_insn "*trunctfdf2_2" + [(set (match_operand:DF 0 "memory_operand" "=m") + (float_truncate:DF + (match_operand:TF 1 "register_operand" "f")))] "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); -}") + if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) + return "fstp%z0\t%y0"; + else + return "fst%z0\t%y0"; +} + [(set_attr "type" "fmov") + (set_attr "mode" "DF")]) -(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"))] +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (float_truncate:DF + (match_operand:TF 1 "register_operand" ""))) + (clobber (match_operand:DF 2 "memory_operand" ""))] "TARGET_80387" - "* return output_fix_trunc (insn, operands);" - [(set_attr "type" "fpop")]) + [(set (match_dup 0) (float_truncate:DF (match_dup 1)))] + "") -(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_split + [(set (match_operand:DF 0 "register_operand" "") + (float_truncate:DF + (match_operand:TF 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_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")]) + +;; %%% Break up all these bad boys. -(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); -}") +;; Signed conversion to DImode. -(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_truncxfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:XF 1 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") -(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 ""))])] +(define_expand "fix_trunctfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:TF 1 "register_operand" "")))] "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_truncdfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 || (TARGET_SSE2 && TARGET_64BIT)" +{ + if (TARGET_64BIT && TARGET_SSE2) + { + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DImode); + emit_insn (gen_fix_truncdfdi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); + DONE; + } +}) -(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" - " +(define_expand "fix_truncsfdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (fix:DI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 || (TARGET_SSE && TARGET_64BIT)" { - 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); -}") + if (TARGET_SSE && TARGET_64BIT) + { + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DImode); + emit_insn (gen_fix_truncsfdi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); + DONE; + } +}) + +;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description +;; of the machinery. +(define_insn_and_split "*fix_truncdi_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") + (fix:DI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "#" + "&& 1" + [(const_int 0)] +{ + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); + if (memory_operand (operands[0], VOIDmode)) + emit_insn (gen_fix_truncdi_memory (operands[0], operands[1], + operands[2], operands[3])); + else + { + operands[4] = assign_386_stack_local (DImode, 0); + emit_insn (gen_fix_truncdi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + } + DONE; +} + [(set_attr "type" "fistp")]) + +(define_insn "fix_truncdi_nomemory" + [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r") + (fix:DI (match_operand 1 "register_operand" "f,f"))) + (use (match_operand:HI 2 "memory_operand" "m,m")) + (use (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:DI 4 "memory_operand" "=m,m")) + (clobber (match_scratch:DF 5 "=&1f,&1f"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "#" + [(set_attr "type" "fistp")]) + +(define_insn "fix_truncdi_memory" + [(set (match_operand:DI 0 "memory_operand" "=m") + (fix:DI (match_operand 1 "register_operand" "f"))) + (use (match_operand:HI 2 "memory_operand" "m")) + (use (match_operand:HI 3 "memory_operand" "m")) + (clobber (match_scratch:DF 4 "=&1f"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)" + "* operands[5] = operands[4]; return output_fix_trunc (insn, operands);" + [(set_attr "type" "fistp")]) -(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. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (fix:DI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:DI 4 "memory_operand" "")) + (clobber (match_scratch 5 ""))] + "reload_completed" + [(parallel [(set (match_dup 4) (fix:DI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 5))]) + (set (match_dup 0) (match_dup 4))] + "") -;; ??? Possibly represent floatunssidf2 here in gcc2. +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (fix:DI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:DI 4 "memory_operand" "")) + (clobber (match_scratch 5 ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (fix:DI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 5))])] + "") -(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);") +;; When SSE available, it is always faster to use it! +(define_insn "fix_truncsfdi_sse" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix:DI (match_operand:SF 1 "nonimmediate_operand" "xm")))] + "TARGET_64BIT && TARGET_SSE" + "cvttss2si{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) -(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_insn "fix_truncdfdi_sse" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix:DI (match_operand:DF 1 "nonimmediate_operand" "Ym")))] + "TARGET_64BIT && TARGET_SSE2" + "cvttsd2si{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) -(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)))] - "") +;; Signed conversion to SImode. -(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_expand "fix_truncxfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:XF 1 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" "") -(define_insn "" - [(set (match_operand:SF 0 "register_operand" "=f") - (float:SF (match_operand:SI 1 "memory_operand" "m")))] +(define_expand "fix_trunctfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:TF 1 "register_operand" "")))] "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_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 || TARGET_SSE2" +{ + if (TARGET_SSE2) + { + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode); + emit_insn (gen_fix_truncdfsi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); + DONE; + } +}) -(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_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (fix:SI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 || TARGET_SSE" +{ + if (TARGET_SSE) + { + rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode); + emit_insn (gen_fix_truncsfsi_sse (out, operands[1])); + if (out != operands[0]) + emit_move_insn (operands[0], out); + DONE; + } +}) + +;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description +;; of the machinery. +(define_insn_and_split "*fix_truncsi_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r") + (fix:SI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + "&& 1" + [(const_int 0)] +{ + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); + if (memory_operand (operands[0], VOIDmode)) + emit_insn (gen_fix_truncsi_memory (operands[0], operands[1], + operands[2], operands[3])); + else + { + operands[4] = assign_386_stack_local (SImode, 0); + emit_insn (gen_fix_truncsi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + } + DONE; +} + [(set_attr "type" "fistp")]) + +(define_insn "fix_truncsi_nomemory" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r") + (fix:SI (match_operand 1 "register_operand" "f,f"))) + (use (match_operand:HI 2 "memory_operand" "m,m")) + (use (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:SI 4 "memory_operand" "=m,m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + [(set_attr "type" "fistp")]) + +(define_insn "fix_truncsi_memory" + [(set (match_operand:SI 0 "memory_operand" "=m") + (fix:SI (match_operand 1 "register_operand" "f"))) + (use (match_operand:HI 2 "memory_operand" "m")) + (use (match_operand:HI 3 "memory_operand" "m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fistp")]) -(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)))] +;; When SSE available, it is always faster to use it! +(define_insn "fix_truncsfsi_sse" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:SF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "cvttss2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "fix_truncdfsi_sse" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:DF 1 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2" + "cvttsd2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:SI 4 "memory_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 4) (fix:SI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3))]) + (set (match_dup 0) (match_dup 4))] "") -(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_split + [(set (match_operand:SI 0 "memory_operand" "") + (fix:SI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:SI 4 "memory_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (fix:SI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3))])] "") -(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")]) +;; Signed conversion to HImode. -(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_expand "fix_truncxfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:XF 1 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") -(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"))] +(define_expand "fix_trunctfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:TF 1 "register_operand" "")))] "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_expand "fix_truncdfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:DF 1 "register_operand" "")))] + "TARGET_80387 && !TARGET_SSE2" "") -(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_expand "fix_truncsfhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (fix:HI (match_operand:SF 1 "register_operand" "")))] + "TARGET_80387 && !TARGET_SSE" + "") -(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" - "#") +;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description +;; of the machinery. +(define_insn_and_split "*fix_trunchi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r") + (fix:HI (match_operand 1 "register_operand" "f,f")))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !reload_completed && !reload_in_progress + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + "" + [(const_int 0)] +{ + operands[2] = assign_386_stack_local (HImode, 1); + operands[3] = assign_386_stack_local (HImode, 2); + if (memory_operand (operands[0], VOIDmode)) + emit_insn (gen_fix_trunchi_memory (operands[0], operands[1], + operands[2], operands[3])); + else + { + operands[4] = assign_386_stack_local (HImode, 0); + emit_insn (gen_fix_trunchi_nomemory (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + } + DONE; +} + [(set_attr "type" "fistp")]) + +(define_insn "fix_trunchi_nomemory" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r") + (fix:HI (match_operand 1 "register_operand" "f,f"))) + (use (match_operand:HI 2 "memory_operand" "m,m")) + (use (match_operand:HI 3 "memory_operand" "m,m")) + (clobber (match_operand:HI 4 "memory_operand" "=m,m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "#" + [(set_attr "type" "fistp")]) + +(define_insn "fix_trunchi_memory" + [(set (match_operand:HI 0 "memory_operand" "=m") + (fix:HI (match_operand 1 "register_operand" "f"))) + (use (match_operand:HI 2 "memory_operand" "m")) + (use (match_operand:HI 3 "memory_operand" "m"))] + "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1])) + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))" + "* return output_fix_trunc (insn, operands);" + [(set_attr "type" "fistp")]) -(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:HI 0 "memory_operand" "") + (fix:HI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:HI 4 "memory_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) (fix:HI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3))])] "") -(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_split + [(set (match_operand:HI 0 "register_operand" "") + (fix:HI (match_operand 1 "register_operand" ""))) + (use (match_operand:HI 2 "memory_operand" "")) + (use (match_operand:HI 3 "memory_operand" "")) + (clobber (match_operand:HI 4 "memory_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 4) (fix:HI (match_dup 1))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 4))]) + (set (match_dup 0) (match_dup 4))] "") -(define_insn "" - [(set (match_operand:DF 0 "register_operand" "=f") - (float:DF (match_operand:SI 1 "memory_operand" "m")))] +;; %% Not used yet. +(define_insn "x86_fnstcw_1" + [(set (match_operand:HI 0 "memory_operand" "=m") + (unspec:HI [(reg:HI 18)] 11))] "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))])] + "fnstcw\t%0" + [(set_attr "length" "2") + (set_attr "mode" "HI") + (set_attr "i387" "1") + (set_attr "ppro_uops" "few")]) + +(define_insn "x86_fldcw_1" + [(set (reg:HI 18) + (unspec:HI [(match_operand:HI 0 "memory_operand" "m")] 12))] "TARGET_80387" - "operands[2] = assign_386_stack_local (HImode, 0);") + "fldcw\t%0" + [(set_attr "length" "2") + (set_attr "mode" "HI") + (set_attr "i387" "1") + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + +;; Conversion between fixed point and floating point. -(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" - "#") +;; Even though we only accept memory inputs, the backend _really_ +;; wants to be able to do this between registers. -(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_insn "floathisf2" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && !TARGET_SSE" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) -(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_expand "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_SSE || TARGET_80387" "") -(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_insn "*floatsisf2_i387" + [(set (match_operand:SF 0 "register_operand" "=f,?f,x") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r,mr")))] + "TARGET_80387 && (!TARGET_SSE || TARGET_MIX_SSE_I387)" + "@ + fild%z1\t%1 + # + cvtsi2ss\t{%1, %0|%0, %1}" + [(set_attr "type" "fmov,multi,sse") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatsisf2_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "mr")))] + "TARGET_SSE" + "cvtsi2ss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) -(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_expand "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))] + "(TARGET_64BIT && TARGET_SSE) || TARGET_80387" + "") -(define_insn "" +(define_insn "*floatdisf2_i387_only" + [(set (match_operand:SF 0 "register_operand" "=f,?f") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE || !TARGET_64BIT || TARGET_MIX_SSE_I387)" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatdisf2_i387" + [(set (match_operand:SF 0 "register_operand" "=f,?f,x") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r,mr")))] + "TARGET_64BIT && TARGET_80387 && (!TARGET_SSE || TARGET_MIX_SSE_I387)" + "@ + fild%z1\t%1 + # + cvtsi2ss{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "fmov,multi,sse") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatdisf2_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (float:SF (match_operand:DI 1 "nonimmediate_operand" "mr")))] + "TARGET_64BIT && TARGET_SSE" + "cvtsi2ss{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF") + (set_attr "fp_int_src" "true")]) + +(define_insn "floathidf2" [(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" - "#") + (float:DF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && !TARGET_SSE2" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) -(define_split +(define_expand "floatsidf2" [(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)))] + (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))] + "" "") -(define_split +(define_insn "*floatsidf2_i387" + [(set (match_operand:DF 0 "register_operand" "=f,?f,Y") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r,mr")))] + "TARGET_80387 && (!TARGET_SSE2 || TARGET_MIX_SSE_I387)" + "@ + fild%z1\t%1 + # + cvtsi2sd\t{%1, %0|%0, %1}" + [(set_attr "type" "fmov,multi,sse") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatsidf2_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (float:DF (match_operand:SI 1 "nonimmediate_operand" "mr")))] + "TARGET_SSE2" + "cvtsi2sd\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) + +(define_expand "floatdidf2" [(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)))] + (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))] + "(TARGET_64BIT && TARGET_SSE2) || TARGET_80387" "") -(define_insn "" - [(set (match_operand:DF 0 "register_operand" "=f") - (float:DF (match_operand:DI 1 "memory_operand" "m")))] +(define_insn "*floatdidf2_i387_only" + [(set (match_operand:DF 0 "register_operand" "=f,?f") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_64BIT)" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatdidf2_i387" + [(set (match_operand:DF 0 "register_operand" "=f,?f,Y") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r,mr")))] + "TARGET_64BIT && TARGET_80387 && (!TARGET_SSE2 || TARGET_MIX_SSE_I387)" + "@ + fild%z1\t%1 + # + cvtsi2sd{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "fmov,multi,sse") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) + +(define_insn "*floatdidf2_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (float:DF (match_operand:DI 1 "nonimmediate_operand" "mr")))] + "TARGET_SSE2" + "cvtsi2sd{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "DF") + (set_attr "fp_int_src" "true")]) + +(define_insn "floathixf2" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] + "!TARGET_64BIT && TARGET_80387" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) + +(define_insn "floathitf2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (float:TF (match_operand:HI 1 "nonimmediate_operand" "m,r")))] "TARGET_80387" - "* return AS1 (fild%z1,%1);" - [(set_attr "type" "fpop")]) + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) -(define_expand "floatsixf2" - [(parallel [(set (match_operand:XF 0 "register_operand" "") - (float:XF (match_operand:SI 1 "nonimmediate_operand" ""))) - (clobber (match_dup 2))])] +(define_insn "floatsixf2" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,r")))] + "!TARGET_64BIT && TARGET_80387" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) + +(define_insn "floatsitf2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (float:TF (match_operand:SI 1 "nonimmediate_operand" "m,r")))] "TARGET_80387" - "operands[2] = assign_386_stack_local (SImode, 0);") + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) -(define_insn "" +(define_insn "floatdixf2" [(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"))] + (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] + "!TARGET_64BIT && TARGET_80387" + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) + +(define_insn "floatditf2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (float:TF (match_operand:DI 1 "nonimmediate_operand" "m,r")))] "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)))] - "") + "@ + fild%z1\t%1 + #" + [(set_attr "type" "fmov,multi") + (set_attr "mode" "XF") + (set_attr "fp_int_src" "true")]) +;; %%% Kill these when reload knows how to do it. (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")]) + [(set (match_operand 0 "register_operand" "") + (float (match_operand 1 "register_operand" "")))] + "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0])) + && FP_REG_P (operands[0])" + [(const_int 0)] +{ + operands[2] = ix86_force_to_memory (GET_MODE (operands[1]), operands[1]); + operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[2])); + ix86_free_from_memory (GET_MODE (operands[1])); + DONE; +}) + +;; Add instructions -(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);") +;; %%% splits for addsidi3 +; [(set (match_operand:DI 0 "nonimmediate_operand" "") +; (plus:DI (match_operand:DI 1 "general_operand" "") +; (zero_extend:DI (match_operand:SI 2 "general_operand" ""))))] -(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_expand "adddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "x86_64_general_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (PLUS, DImode, operands); DONE;") + +(define_insn "*adddi3_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "general_operand" "roiF,riF"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" "#") (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)))] - "") + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(parallel [(set (reg:CC 17) (unspec:CC [(match_dup 1) (match_dup 2)] 12)) + (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) + (parallel [(set (match_dup 3) + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_dup 4)) + (match_dup 5))) + (clobber (reg:CC 17))])] + "split_di (operands+0, 1, operands+0, operands+3); + split_di (operands+1, 1, operands+1, operands+4); + split_di (operands+2, 1, operands+2, operands+5);") + +(define_insn "*adddi3_carry_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (plus:DI (plus:DI (ltu:DI (reg:CC 17) (const_int 0)) + (match_operand:DI 1 "nonimmediate_operand" "%0,0")) + (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" + "adc{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "mode" "DI") + (set_attr "ppro_uops" "few")]) + +(define_insn "*adddi3_cc_rex64" + [(set (reg:CC 17) (unspec:CC [(match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rm")] 12)) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (plus:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" + "add{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*addsi3_carry" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "nonimmediate_operand" "%0,0")) + (match_operand:SI 2 "general_operand" "ri,rm"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (PLUS, SImode, operands)" + "adc{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) + +(define_insn "*addsi3_carry_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_operand:SI 1 "nonimmediate_operand" "%0")) + (match_operand:SI 2 "general_operand" "rim")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" + "adc{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) + +(define_insn "*addsi3_cc" + [(set (reg:CC 17) (unspec:CC [(match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")] 12)) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (plus:SI (match_dup 1) (match_dup 2)))] + "ix86_binary_operator_ok (PLUS, SImode, operands)" + "add{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "addqi3_cc" + [(set (reg:CC 17) (unspec:CC [(match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qi,qm")] 12)) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (plus:QI (match_dup 1) (match_dup 2)))] + "ix86_binary_operator_ok (PLUS, QImode, operands)" + "add{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) -(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_expand "addsi3" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "" + "ix86_expand_binary_operator (PLUS, SImode, operands); DONE;") -(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_insn "*lea_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "address_operand" "p"))] + "!TARGET_64BIT" + "lea{l}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) -(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 "*lea_1_rex64" + [(set (match_operand:SI 0 "register_operand" "=r") + (subreg:SI (match_operand:DI 1 "address_operand" "p") 0))] + "TARGET_64BIT" + "lea{l}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn "*lea_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (subreg:SI (match_operand:DI 1 "address_operand" "p") 0)))] + "TARGET_64BIT" + "lea{l}\t{%a1, %k0|%k0, %a1}" + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn "*lea_2_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (match_operand:DI 1 "address_operand" "p"))] + "TARGET_64BIT" + "lea{q}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "lea") + (set_attr "mode" "DI")]) + +;; The lea patterns for non-Pmodes needs to be matched by several +;; insns converted to real lea by splitters. + +(define_insn_and_split "*lea_general_1" + [(set (match_operand 0 "register_operand" "=r") + (plus (plus (match_operand 1 "register_operand" "r") + (match_operand 2 "register_operand" "r")) + (match_operand 3 "immediate_operand" "i")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_size) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && GET_MODE (operands[0]) == GET_MODE (operands[2]) + && (GET_MODE (operands[0]) == GET_MODE (operands[3]) + || GET_MODE (operands[3]) == VOIDmode)" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + operands[3] = gen_lowpart (Pmode, operands[3]); + pat = gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode, operands[1], operands[2]), + operands[3]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "immediate_operand" "i"))))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (plus:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + operands[3] = gen_lowpart (Pmode, operands[3]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_2" + [(set (match_operand 0 "register_operand" "=r") + (plus (mult (match_operand 1 "register_operand" "r") + (match_operand 2 "const248_operand" "i")) + (match_operand 3 "nonmemory_operand" "ri")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_size) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && (GET_MODE (operands[0]) == GET_MODE (operands[3]) + || GET_MODE (operands[3]) == VOIDmode)" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + pat = gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], operands[2]), + operands[3]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_2_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const248_operand" "n")) + (match_operand:SI 3 "nonmemory_operand" "ri"))))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (mult:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_3" + [(set (match_operand 0 "register_operand" "=r") + (plus (plus (mult (match_operand 1 "register_operand" "r") + (match_operand 2 "const248_operand" "i")) + (match_operand 3 "register_operand" "r")) + (match_operand 4 "immediate_operand" "i")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_size) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && GET_MODE (operands[0]) == GET_MODE (operands[3])" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + operands[4] = gen_lowpart (Pmode, operands[4]); + pat = gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], + operands[2]), + operands[3]), + operands[4]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_3_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const248_operand" "n")) + (match_operand:SI 3 "register_operand" "r")) + (match_operand:SI 4 "immediate_operand" "i"))))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (plus:DI (mult:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) + (match_dup 4)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + operands[4] = gen_lowpart (Pmode, operands[4]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn "*adddi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,r") + (match_operand:DI 2 "x86_64_general_operand" "rme,re,re"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{q}\t{%a2, %0|%0, %a2}"; -(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" - "#") + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; + else + abort (); -(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)))] - "") + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{q}\t{%2, %0|%0, %2}"; + } + return "add{q}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "lea") + ; Current assemblers are broken and do not allow @GOTOFF in + ; ought but a memory context. + (match_operand:DI 2 "pic_symbolic_operand" "") + (const_string "lea") + (match_operand:DI 2 "incdec_operand" "") + (const_string "incdec") + ] + (const_string "alu"))) + (set_attr "mode" "DI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. (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)))] + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "x86_64_nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (plus:DI (match_dup 1) + (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"))] - "" - "* +(define_insn "*adddi_2_rex64" + [(set (reg 17) + (compare + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "rme,re")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") + (plus:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, DImode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" { - rtx low[3], high[3], xops[7]; - - CC_STATUS_INIT; + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; + else + abort (); - split_di (operands, 2, low, high); - high[2] = const0_rtx; - low[2] = operands[2]; + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* ???? We ought to handle there the 32bit case too + - do we need new constrant? */ + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{q}\t{%2, %0|%0, %2}"; + } + return "add{q}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:DI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "DI")]) + +(define_insn "*adddi_3_rex64" + [(set (reg 17) + (compare (neg:DI (match_operand:DI 2 "x86_64_general_operand" "rme")) + (match_operand:DI 1 "x86_64_general_operand" "%0"))) + (clobber (match_scratch:DI 0 "=r"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCZmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; + else + abort (); - if (!rtx_equal_p (operands[0], operands[1])) + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* ???? We ought to handle there the 32bit case too + - do we need new constrant? */ + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{q}\t{%2, %0|%0, %2}"; + } + return "add{q}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:DI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "DI")]) + +; For comparisons against 1, -1 and 128, we may generate better code +; by converting cmp to add, inc or dec as done by peephole2. This pattern +; is matched then. We can't accept general immediate, because for +; case of overflows, the result is messed up. +; This pattern also don't hold of 0x8000000000000000, since the value overflows +; when negated. +; Also carry flag is reversed compared to cmp, so this conversion is valid +; only for comparisons not depending on it. +(define_insn "*adddi_4_rex64" + [(set (reg 17) + (compare (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:DI 2 "x86_64_immediate_operand" "e"))) + (clobber (match_scratch:DI 0 "=rm"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCGCmode)" +{ + switch (get_attr_type (insn)) { - xops[0] = high[0]; - xops[1] = low[0]; - xops[2] = high[1]; - xops[3] = low[1]; + case TYPE_INCDEC: + if (operands[2] == constm1_rtx) + return "inc{q}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{q}\t%0"; + else + abort(); - 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); - } + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if ((INTVAL (operands[2]) == -128 + || (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) != 128)) + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) + return "sub{q}\t{%2, %0|%0, %2}"; + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "add{q}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:DI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "DI")]) + +(define_insn "*adddi_5_rex64" + [(set (reg 17) + (compare + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "x86_64_general_operand" "rme")) + (const_int 0))) + (clobber (match_scratch:DI 0 "=r"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCGOCmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{q}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{q}\t%0"; 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; - } + abort(); + + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{q}\t{%2, %0|%0, %2}"; + } + return "add{q}\t{%2, %0|%0, %2}"; } +} + [(set (attr "type") + (if_then_else (match_operand:DI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "DI")]) - 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"))] - "" - "* +(define_insn "*addsi_1" + [(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" "rmni,rni,rni"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (PLUS, SImode, operands)" { - rtx low[3], high[3], xops[7]; + switch (get_attr_type (insn)) + { + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{l}\t{%a2, %0|%0, %a2}"; - CC_STATUS_INIT; + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; + else + abort(); - split_di (operands, 2, low, high); - high[2] = const0_rtx; - low[2] = operands[2]; + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); - if (!rtx_equal_p (operands[0], operands[1])) + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %0|%0, %2}"; + } + return "add{l}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "lea") + ; Current assemblers are broken and do not allow @GOTOFF in + ; ought but a memory context. + (match_operand:SI 2 "pic_symbolic_operand" "") + (const_string "lea") + (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + ] + (const_string "alu"))) + (set_attr "mode" "SI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand 0 "register_operand" "") + (plus (match_operand 1 "register_operand" "") + (match_operand 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(const_int 0)] +{ + rtx pat; + /* In -fPIC mode the constructs like (const (unspec [symbol_ref])) + may confuse gen_lowpart. */ + if (GET_MODE (operands[0]) != Pmode) + { + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + } + operands[0] = gen_lowpart (SImode, operands[0]); + pat = gen_rtx_PLUS (Pmode, operands[1], operands[2]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +}) + +;; It may seem that nonimmediate operand is proper one for operand 1. +;; The addsi_1 pattern allows nonimmediate operand at that place and +;; we take care in ix86_binary_operator_ok to not allow two memory +;; operands so proper swapping will be done in reload. This allow +;; patterns constructed from addsi_1 to match. +(define_insn "addsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,r") + (match_operand:SI 2 "general_operand" "rmni,rni")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" +{ + switch (get_attr_type (insn)) { - xops[0] = high[0]; - xops[1] = low[0]; - xops[2] = high[1]; - xops[3] = low[1]; + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{l}\t{%a2, %k0|%k0, %a2}"; + + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; + else + abort(); - 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); - } + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %k0|%k0, %2}"; + } + return "add{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + ; Current assemblers are broken and do not allow @GOTOFF in + ; ought but a memory context. + (match_operand:SI 2 "pic_symbolic_operand" "") + (const_string "lea") + (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + ] + (const_string "alu"))) + (set_attr "mode" "SI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (match_dup 1) (match_dup 2)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); +}) + +(define_insn "*addsi_2" + [(set (reg 17) + (compare + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "rmni,rni")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") + (plus:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, SImode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; 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; - } + abort(); + + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %0|%0, %2}"; + } + return "add{l}\t{%2, %0|%0, %2}"; } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*addsi_2_zext" + [(set (reg 17) + (compare + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rmni")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, SImode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; + else + abort(); - 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")]) + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %k0|%k0, %2}"; + } + return "add{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + +(define_insn "*addsi_3" + [(set (reg 17) + (compare (neg:SI (match_operand:SI 2 "general_operand" "rmni")) + (match_operand:SI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:SI 0 "=r"))] + "ix86_match_ccmode (insn, CCZmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; + else + abort(); -(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"))] - "" - "* + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %0|%0, %2}"; + } + return "add{l}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*addsi_3_zext" + [(set (reg 17) + (compare (neg:SI (match_operand:SI 2 "general_operand" "rmni")) + (match_operand:SI 1 "nonimmediate_operand" "%0"))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCZmode) + && ix86_binary_operator_ok (PLUS, SImode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" { - rtx low[3], high[3], xops[7], temp; + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{l}\t%k0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%k0"; + else + abort(); - CC_STATUS_INIT; + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %k0|%k0, %2}"; + } + return "add{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + +; For comparisons agains 1, -1 and 128, we may generate better code +; by converting cmp to add, inc or dec as done by peephole2. This pattern +; is matched then. We can't accept general immediate, because for +; case of overflows, the result is messed up. +; This pattern also don't hold of 0x80000000, since the value overflows +; when negated. +; Also carry flag is reversed compared to cmp, so this conversion is valid +; only for comparisons not depending on it. +(define_insn "*addsi_4" + [(set (reg 17) + (compare (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "const_int_operand" "n"))) + (clobber (match_scratch:SI 0 "=rm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xffffffff) != 0x80000000" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == constm1_rtx) + return "inc{l}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{l}\t%0"; + else + abort(); - if (rtx_equal_p (operands[0], operands[2])) + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if ((INTVAL (operands[2]) == -128 + || (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) != 128))) + return "sub{l}\t{%2, %0|%0, %2}"; + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "add{l}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + +(define_insn "*addsi_5" + [(set (reg 17) + (compare + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rmni")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "ix86_match_ccmode (insn, CCGOCmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) { - temp = operands[1]; - operands[1] = operands[2]; - operands[2] = temp; + case TYPE_INCDEC: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (operands[2] == const1_rtx) + return "inc{l}\t%0"; + else if (operands[2] == constm1_rtx) + return "dec{l}\t%0"; + else + abort(); + + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %0|%0, %2}"; + } + return "add{l}\t{%2, %0|%0, %2}"; } +} + [(set (attr "type") + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) - split_di (operands, 3, low, high); - if (!rtx_equal_p (operands[0], operands[1])) +(define_expand "addhi3" + [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (PLUS, HImode, operands); DONE;") + +;; %%% After Dave's SUBREG_BYTE stuff goes in, re-enable incb %ah +;; type optimizations enabled by define-splits. This is not important +;; for PII, and in fact harmful because of partial register stalls. + +(define_insn "*addhi_1_lea" + [(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,rni"))) + (clobber (reg:CC 17))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, HImode, operands)" +{ + switch (get_attr_type (insn)) { - xops[0] = high[0]; - xops[1] = low[0]; - xops[2] = high[1]; - xops[3] = low[1]; + case TYPE_LEA: + return "#"; + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "dec{w}\t%0"; + abort(); - if (GET_CODE (operands[0]) != MEM) + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) { - output_asm_insn (AS2 (mov%L1,%3,%1), xops); - output_asm_insn (AS2 (mov%L0,%2,%0), xops); + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; } - else + return "add{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (eq_attr "alternative" "2") + (const_string "lea") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu")))) + (set_attr "mode" "HI,HI,SI")]) + +(define_insn "*addhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm"))) + (clobber (reg:CC 17))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, HImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "dec{w}\t%0"; + abort(); + + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) { - 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; + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; } + return "add{w}\t{%2, %0|%0, %2}"; } - - cc_status.value1 = high[0]; - cc_status.flags = CC_NO_OVERFLOW; - - if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG) +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "HI")]) + +(define_insn "*addhi_2" + [(set (reg 17) + (compare + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rmni,rni")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (plus:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, HImode, operands)" +{ + switch (get_attr_type (insn)) { - xops[0] = high[0]; - xops[1] = low[0]; - xops[2] = high[2]; - xops[3] = low[2]; - xops[4] = operands[3]; + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "dec{w}\t%0"; + abort(); - 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); + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; } - - else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "HI")]) + +(define_insn "*addhi_3" + [(set (reg 17) + (compare (neg:HI (match_operand:HI 2 "general_operand" "rmni")) + (match_operand:HI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:HI 0 "=r"))] + "ix86_match_ccmode (insn, CCZmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" +{ + switch (get_attr_type (insn)) { - 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); + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "dec{w}\t%0"; + abort(); - 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);") + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "HI")]) + +; See comments above addsi_3_imm for details. +(define_insn "*addhi_4" + [(set (reg 17) + (compare (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "const_int_operand" "n"))) + (clobber (match_scratch:HI 0 "=rm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xffff) != 0x8000" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "inc{w}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{w}\t%0"; + else + abort(); -(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)" - "* + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if ((INTVAL (operands[2]) == -128 + || (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) != 128))) + return "sub{w}\t{%2, %0|%0, %2}"; + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "add{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "SI")]) + + +(define_insn "*addhi_5" + [(set (reg 17) + (compare + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0") + (match_operand:HI 2 "general_operand" "rmni")) + (const_int 0))) + (clobber (match_scratch:HI 0 "=r"))] + "ix86_match_ccmode (insn, CCGOCmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" { - if (REG_P (operands[0]) && REG_P (operands[1]) - && (REG_P (operands[2]) || CONSTANT_P (operands[2])) - && REGNO (operands[0]) != REGNO (operands[1])) + switch (get_attr_type (insn)) { - if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) - return AS2 (add%L0,%1,%0); + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) + return "dec{w}\t%0"; + abort(); - if (operands[2] == stack_pointer_rtx) + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) { - rtx temp; - - temp = operands[1]; - operands[1] = operands[2]; - operands[2] = temp; + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; } + return "add{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "HI")]) - if (operands[2] != stack_pointer_rtx) +(define_expand "addqi3" + [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (PLUS, QImode, operands); DONE;") + +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*addqi_1_lea" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r") + (match_operand:QI 2 "general_operand" "qn,qmn,rn,rn"))) + (clobber (reg:CC 17))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, QImode, operands)" +{ + int widen = (which_alternative == 2); + switch (get_attr_type (insn)) + { + case TYPE_LEA: + return "#"; + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; + abort(); + + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) { - CC_STATUS_INIT; - operands[1] = SET_SRC (PATTERN (insn)); - return AS2 (lea%L0,%a1,%0); + operands[2] = GEN_INT (-INTVAL (operands[2])); + if (widen) + return "sub{l}\t{%2, %k0|%k0, %2}"; + else + return "sub{b}\t{%2, %0|%0, %2}"; } + if (widen) + return "add{l}\t{%k2, %k0|%k0, %k2}"; + else + return "add{b}\t{%2, %0|%0, %2}"; } - - 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) +} + [(set (attr "type") + (if_then_else (eq_attr "alternative" "3") + (const_string "lea") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu")))) + (set_attr "mode" "QI,QI,SI,SI")]) + +(define_insn "*addqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qn,qmn,rn"))) + (clobber (reg:CC 17))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, QImode, operands)" +{ + int widen = (which_alternative == 2); + switch (get_attr_type (insn)) { - /* 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")]) + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; + abort(); -;; 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"))] - "" - "* + default: + /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + if (widen) + return "sub{l}\t{%2, %k0|%k0, %2}"; + else + return "sub{b}\t{%2, %0|%0, %2}"; + } + if (widen) + return "add{l}\t{%k2, %k0|%k0, %k2}"; + else + return "add{b}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI,QI,SI")]) + +(define_insn "*addqi_2" + [(set (reg 17) + (compare + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qmni,qni")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") + (plus:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, QImode, operands)" { - /* 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))) + switch (get_attr_type (insn)) { - operands[1] = XEXP (operands[1], 1); - - if (operands[1] == const1_rtx) - return AS1 (inc%L0,%0); + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + abort(); - if (operands[1] == constm1_rtx) - return AS1 (dec%L0,%0); - - return AS2 (add%L0,%1,%0); + default: + /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{b}\t{%2, %0|%0, %2}"; + } + return "add{b}\t{%2, %0|%0, %2}"; } - - 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)" - "* +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + +(define_insn "*addqi_3" + [(set (reg 17) + (compare (neg:QI (match_operand:QI 2 "general_operand" "qmni")) + (match_operand:QI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:QI 0 "=q"))] + "ix86_match_ccmode (insn, CCZmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" { - if (REG_P (operands[0]) && REG_P (operands[1]) - && (REG_P (operands[2]) || CONSTANT_P (operands[2])) - && REGNO (operands[0]) != REGNO (operands[1])) + switch (get_attr_type (insn)) { - if (operands[2] == stack_pointer_rtx) - abort (); + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + 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); + default: + /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{b}\t{%2, %0|%0, %2}"; + } + return "add{b}\t{%2, %0|%0, %2}"; } - - /* ??? 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)) +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + +; See comments above addsi_3_imm for details. +(define_insn "*addqi_4" + [(set (reg 17) + (compare (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "n"))) + (clobber (match_scratch:QI 0 "=qm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xff) != 0x80" +{ + switch (get_attr_type (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); + case TYPE_INCDEC: + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "inc{b}\t%0"; + else if (operands[2] == const1_rtx) + return "dec{b}\t%0"; + else + abort(); - operands[2] = GEN_INT (byteval); - return AS2 (add%B0,%2,%h0); + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "add{b}\t{%2, %0|%0, %2}"; + } + return "sub{b}\t{%2, %0|%0, %2}"; } - - /* 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)) +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + + +(define_insn "*addqi_5" + [(set (reg 17) + (compare + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0") + (match_operand:QI 2 "general_operand" "qmni")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=q"))] + "ix86_match_ccmode (insn, CCGOCmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" +{ + switch (get_attr_type (insn)) { - CC_STATUS_INIT; + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%0"; + abort(); - if (GET_CODE (operands[2]) == CONST_INT) + default: + /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) { - 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]); + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{b}\t{%2, %0|%0, %2}"; } - return AS2 (add%L0,%k2,%k0); + return "add{b}\t{%2, %0|%0, %2}"; } +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + + +(define_insn "addqi_ext_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "Qmn"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%h0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%h0"; + abort(); - 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)" - "* + default: + return "add{b}\t{%2, %h0|%h0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + +(define_insn "*addqi_ext_1_rex64" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "nonmemory_operand" "Qn"))) + (clobber (reg:CC 17))] + "TARGET_64BIT" { - 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])))) + switch (get_attr_type (insn)) { - if (operands[2] == stack_pointer_rtx) - abort (); + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%h0"; + else if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) + return "dec{b}\t%h0"; + 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; -;}") + default: + return "add{b}\t{%2, %h0|%h0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + +(define_insn "*addqi_ext_2" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "%0") + (const_int 8) + (const_int 8)) + (zero_extract:SI + (match_operand 2 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))) + (clobber (reg:CC 17))] + "" + "add{b}\t{%h2, %h0|%h0, %h2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) ;; The patterns that match these are at the end of this file. @@ -3706,204 +6878,316 @@ [(set (match_operand:XF 0 "register_operand" "") (plus:XF (match_operand:XF 1 "register_operand" "") (match_operand:XF 2 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") + +(define_expand "addtf3" + [(set (match_operand:TF 0 "register_operand" "") + (plus:TF (match_operand:TF 1 "register_operand" "") + (match_operand:TF 2 "register_operand" "")))] "TARGET_80387" "") (define_expand "adddf3" [(set (match_operand:DF 0 "register_operand" "") - (plus:DF (match_operand:DF 1 "nonimmediate_operand" "") + (plus:DF (match_operand:DF 1 "register_operand" "") (match_operand:DF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" "") (define_expand "addsf3" [(set (match_operand:SF 0 "register_operand" "") - (plus:SF (match_operand:SF 1 "nonimmediate_operand" "") + (plus:SF (match_operand:SF 1 "register_operand" "") (match_operand:SF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || TARGET_SSE_MATH" "") -;;- 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]; +;; Subtract instructions - 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; - } - } +;; %%% splits for subsidi3 - 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"))] +(define_expand "subdi3" + [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "x86_64_general_operand" ""))) + (clobber (reg:CC 17))])] "" - "* -{ - 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); - + "ix86_expand_binary_operator (MINUS, DImode, operands); DONE;") + +(define_insn "*subdi3_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "general_operand" "roiF,riF"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "#") - RET; -}" - [(set_attr "type" "binary")]) +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(parallel [(set (reg:CC 17) (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))]) + (parallel [(set (match_dup 3) + (minus:SI (match_dup 4) + (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_dup 5)))) + (clobber (reg:CC 17))])] + "split_di (operands+0, 1, operands+0, operands+3); + split_di (operands+1, 1, operands+1, operands+4); + split_di (operands+2, 1, operands+2, operands+5);") + +(define_insn "subdi3_carry_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (plus:DI (ltu:DI (reg:CC 17) (const_int 0)) + (match_operand:DI 2 "x86_64_general_operand" "re,rm")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" + "sbb{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") + (set_attr "mode" "DI")]) + +(define_insn "*subdi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" + "sub{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*subdi_2_rex64" + [(set (reg 17) + (compare + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rm")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (minus:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, DImode, operands)" + "sub{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*subdi_3_rex63" + [(set (reg 17) + (compare (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (minus:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + + +(define_insn "subsi3_carry" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_operand:SI 2 "general_operand" "ri,rm")))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (MINUS, SImode, operands)" + "sbb{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) + +(define_insn "subsi3_carry_zext" + [(set (match_operand:DI 0 "register_operand" "=rm,r") + (zero_extend:DI + (minus:SI (match_operand:SI 1 "register_operand" "0,0") + (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_operand:SI 2 "general_operand" "ri,rm"))))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sbb{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) (define_expand "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] "" - "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);") + "ix86_expand_binary_operator (MINUS, SImode, operands); DONE;") -(define_insn "" +(define_insn "*subsi_1" [(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")))] + (match_operand:SI 2 "general_operand" "ri,rm"))) + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, SImode, operands)" - "* return AS2 (sub%L0,%2,%0);" - [(set_attr "type" "binary")]) + "sub{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rim")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi_2" + [(set (reg 17) + (compare + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "ri,rm")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi_2_zext" + [(set (reg 17) + (compare + (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_dup 1) + (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi_3" + [(set (reg 17) + (compare (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "ri,rm"))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi_3_zext" + [(set (reg 17) + (compare (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "general_operand" "rim"))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_dup 1) + (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) (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 "" + [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (MINUS, HImode, operands); DONE;") + +(define_insn "*subhi_1" [(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")))] + (match_operand:HI 2 "general_operand" "ri,rm"))) + (clobber (reg:CC 17))] "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")]) + "sub{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*subhi_2" + [(set (reg 17) + (compare + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:HI 2 "general_operand" "ri,rm")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (minus:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, HImode, operands)" + "sub{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*subhi_3" + [(set (reg 17) + (compare (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:HI 2 "general_operand" "ri,rm"))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (minus:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, HImode, operands)" + "sub{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) (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 "" + [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") + (minus:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (MINUS, QImode, operands); DONE;") + +(define_insn "*subqi_1" [(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")))] + (match_operand:QI 2 "general_operand" "qn,qmn"))) + (clobber (reg:CC 17))] "ix86_binary_operator_ok (MINUS, QImode, operands)" - "* return AS2 (sub%B0,%2,%0);" - [(set_attr "type" "binary")]) + "sub{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*subqi_2" + [(set (reg 17) + (compare + (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "general_operand" "qi,qm")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q") + (minus:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, QImode, operands)" + "sub{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*subqi_3" + [(set (reg 17) + (compare (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "general_operand" "qi,qm"))) + (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q") + (minus:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, QImode, operands)" + "sub{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) ;; The patterns that match these are at the end of this file. @@ -3911,115 +7195,325 @@ [(set (match_operand:XF 0 "register_operand" "") (minus:XF (match_operand:XF 1 "register_operand" "") (match_operand:XF 2 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") + +(define_expand "subtf3" + [(set (match_operand:TF 0 "register_operand" "") + (minus:TF (match_operand:TF 1 "register_operand" "") + (match_operand:TF 2 "register_operand" "")))] "TARGET_80387" "") (define_expand "subdf3" [(set (match_operand:DF 0 "register_operand" "") - (minus:DF (match_operand:DF 1 "nonimmediate_operand" "") + (minus:DF (match_operand:DF 1 "register_operand" "") (match_operand:DF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" "") (define_expand "subsf3" [(set (match_operand:SF 0 "register_operand" "") - (minus:SF (match_operand:SF 1 "nonimmediate_operand" "") + (minus:SF (match_operand:SF 1 "register_operand" "") (match_operand:SF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || TARGET_SSE_MATH" "") -;;- 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") +;; Multiply instructions + +(define_expand "muldi3" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (mult:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "x86_64_general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" + "") -(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")))] +(define_insn "*muldi3_1_rex64" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%rm,0,0") + (match_operand:DI 2 "x86_64_general_operand" "K,e,mr"))) + (clobber (reg:CC 17))] + "TARGET_64BIT + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "@ + imul{q}\t{%2, %1, %0|%0, %1, %2} + imul{q}\t{%2, %1, %0|%0, %1, %2} + imul{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "imul") + (set_attr "prefix_0f" "0,0,1") + (set_attr "mode" "DI")]) + +(define_expand "mulsi3" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] "" - "* -{ - 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 "*mulsi3_1" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,0,0") + (match_operand:SI 2 "general_operand" "K,i,mr"))) + (clobber (reg:CC 17))] + "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" + ; For the {r,0,i} alternative (i.e., register <- register * immediate), + ; there are two ways of writing the exact same machine instruction + ; in assembly language. One, for example, is: + ; + ; imul $12, %eax + ; + ; while the other is: + ; + ; imul $12, %eax, %eax + ; + ; The first is simply short-hand for the latter. But, some assemblers, + ; like the SCO OSR5 COFF assembler, don't handle the first form. + "@ + imul{l}\t{%2, %1, %0|%0, %1, %2} + imul{l}\t{%2, %1, %0|%0, %1, %2} + imul{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "imul") + (set_attr "prefix_0f" "0,0,1") + (set_attr "mode" "SI")]) + +(define_insn "*mulsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (zero_extend:DI + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,0,0") + (match_operand:SI 2 "general_operand" "K,i,mr")))) + (clobber (reg:CC 17))] + "TARGET_64BIT + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + ; For the {r,0,i} alternative (i.e., register <- register * immediate), + ; there are two ways of writing the exact same machine instruction + ; in assembly language. One, for example, is: + ; + ; imul $12, %eax + ; + ; while the other is: + ; + ; imul $12, %eax, %eax + ; + ; The first is simply short-hand for the latter. But, some assemblers, + ; like the SCO OSR5 COFF assembler, don't handle the first form. + "@ + imul{l}\t{%2, %1, %k0|%k0, %1, %2} + imul{l}\t{%2, %1, %k0|%k0, %1, %2} + imul{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "imul") + (set_attr "prefix_0f" "0,0,1") + (set_attr "mode" "SI")]) + +(define_expand "mulhi3" + [(parallel [(set (match_operand:HI 0 "register_operand" "") + (mult:HI (match_operand:HI 1 "register_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_HIMODE_MATH" + "") + +(define_insn "*mulhi3_1" + [(set (match_operand:HI 0 "register_operand" "=r,r,r") + (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,0,0") + (match_operand:HI 2 "general_operand" "K,i,mr"))) + (clobber (reg:CC 17))] + "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM" + ; %%% There was a note about "Assembler has weird restrictions", + ; concerning alternative 1 when op1 == op0. True? + "@ + imul{w}\t{%2, %1, %0|%0, %1, %2} + imul{w}\t{%2, %1, %0|%0, %1, %2} + imul{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "imul") + (set_attr "prefix_0f" "0,0,1") + (set_attr "mode" "HI")]) + +(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"))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "mul{b}\t%2" + [(set_attr "type" "imul") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) (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")]) + (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "mul{b}\t%2" + [(set_attr "type" "imul") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) (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")]) - + (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "imul{b}\t%2" + [(set_attr "type" "imul") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) + +(define_insn "umulditi3" + [(set (match_operand:TI 0 "register_operand" "=A") + (mult:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "%0")) + (zero_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "mul{q}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "length_immediate" "0") + (set_attr "mode" "DI")]) + +;; We can't use this pattern in 64bit mode, since it results in two separate 32bit registers (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")]) + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "mul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) + +(define_insn "mulditi3" + [(set (match_operand:TI 0 "register_operand" "=A") + (mult:TI (sign_extend:TI (match_operand:DI 1 "register_operand" "%0")) + (sign_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "imul{q}\t%2" + [(set_attr "type" "imul") + (set_attr "length_immediate" "0") + (set_attr "mode" "DI")]) (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")]) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "imul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) + +(define_insn "*umuldi3_highpart_rex64" + [(set (match_operand:DI 0 "register_operand" "=d") + (truncate:DI + (lshiftrt:TI + (mult:TI (zero_extend:TI + (match_operand:DI 1 "register_operand" "%a")) + (zero_extend:TI + (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (const_int 64)))) + (clobber (match_scratch:DI 3 "=a")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "mul{q}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "length_immediate" "0") + (set_attr "mode" "DI")]) (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")]) + (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")) + (clobber (reg:CC 17))] + "" + "mul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) + +(define_insn "*umulsi3_highpart_zext" + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extend:DI (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")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "mul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) + +(define_insn "*smuldi3_highpart_rex64" + [(set (match_operand:DI 0 "register_operand" "=d") + (truncate:DI + (lshiftrt:TI + (mult:TI (sign_extend:TI + (match_operand:DI 1 "register_operand" "%a")) + (sign_extend:TI + (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (const_int 64)))) + (clobber (match_scratch:DI 3 "=a")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "imul{q}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "mode" "DI")]) (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")]) + (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")) + (clobber (reg:CC 17))] + "" + "imul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) + +(define_insn "*smulsi3_highpart_zext" + [(set (match_operand:DI 0 "register_operand" "=d") + (zero_extend:DI (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")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "imul{l}\t%2" + [(set_attr "type" "imul") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) ;; The patterns that match these are at the end of this file. @@ -4027,6 +7521,13 @@ [(set (match_operand:XF 0 "register_operand" "") (mult:XF (match_operand:XF 1 "register_operand" "") (match_operand:XF 2 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") + +(define_expand "multf3" + [(set (match_operand:TF 0 "register_operand" "") + (mult:TF (match_operand:TF 1 "register_operand" "") + (match_operand:TF 2 "register_operand" "")))] "TARGET_80387" "") @@ -4034,32 +7535,39 @@ [(set (match_operand:DF 0 "register_operand" "") (mult:DF (match_operand:DF 1 "register_operand" "") (match_operand:DF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" "") (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" + "TARGET_80387 || TARGET_SSE_MATH" "") -;;- divide instructions +;; 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") + (match_operand:QI 2 "nonimmediate_operand" "qm"))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "idiv{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI") + (set_attr "ppro_uops" "few")]) (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")]) + (match_operand:QI 2 "nonimmediate_operand" "qm"))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "div{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI") + (set_attr "ppro_uops" "few")]) ;; The patterns that match these are at the end of this file. @@ -4067,6 +7575,13 @@ [(set (match_operand:XF 0 "register_operand" "") (div:XF (match_operand:XF 1 "register_operand" "") (match_operand:XF 2 "register_operand" "")))] + "!TARGET_64BIT && TARGET_80387" + "") + +(define_expand "divtf3" + [(set (match_operand:TF 0 "register_operand" "") + (div:TF (match_operand:TF 1 "register_operand" "") + (match_operand:TF 2 "register_operand" "")))] "TARGET_80387" "") @@ -4074,2811 +7589,5939 @@ [(set (match_operand:DF 0 "register_operand" "") (div:DF (match_operand:DF 1 "register_operand" "") (match_operand:DF 2 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)" "") (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" + "TARGET_80387 || TARGET_SSE_MATH" "") ;; Remainder instructions. -(define_insn "divmodsi4" +(define_expand "divmoddi4" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (div:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonimmediate_operand" ""))) + (set (match_operand:DI 3 "register_operand" "") + (mod:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" + "") + +;; Allow to come the parameter in eax or edx to avoid extra moves. +;; Penalize eax case sligthly because it results in worse scheduling +;; of code. +(define_insn "*divmoddi4_nocltd_rex64" + [(set (match_operand:DI 0 "register_operand" "=&a,?a") + (div:DI (match_operand:DI 2 "register_operand" "1,0") + (match_operand:DI 3 "nonimmediate_operand" "rm,rm"))) + (set (match_operand:DI 1 "register_operand" "=&d,&d") + (mod:DI (match_dup 2) (match_dup 3))) + (clobber (reg:CC 17))] + "TARGET_64BIT && !optimize_size && !TARGET_USE_CLTD" + "#" + [(set_attr "type" "multi")]) + +(define_insn "*divmoddi4_cltd_rex64" + [(set (match_operand:DI 0 "register_operand" "=a") + (div:DI (match_operand:DI 2 "register_operand" "a") + (match_operand:DI 3 "nonimmediate_operand" "rm"))) + (set (match_operand:DI 1 "register_operand" "=&d") + (mod:DI (match_dup 2) (match_dup 3))) + (clobber (reg:CC 17))] + "TARGET_64BIT && (optimize_size || TARGET_USE_CLTD)" + "#" + [(set_attr "type" "multi")]) + +(define_insn "*divmoddi_noext_rex64" + [(set (match_operand:DI 0 "register_operand" "=a") + (div:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:DI 3 "register_operand" "=d") + (mod:DI (match_dup 1) (match_dup 2))) + (use (match_operand:DI 4 "register_operand" "3")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "idiv{q}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "DI") + (set_attr "ppro_uops" "few")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (div:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonimmediate_operand" ""))) + (set (match_operand:DI 3 "register_operand" "") + (mod:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed" + [(parallel [(set (match_dup 3) + (ashiftrt:DI (match_dup 4) (const_int 63))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 0) + (div:DI (reg:DI 0) (match_dup 2))) + (set (match_dup 3) + (mod:DI (reg:DI 0) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))])] +{ + /* Avoid use of cltd in favour of a mov+shift. */ + if (!TARGET_USE_CLTD && !optimize_size) + { + if (true_regnum (operands[1])) + emit_move_insn (operands[0], operands[1]); + else + emit_move_insn (operands[3], operands[1]); + operands[4] = operands[3]; + } + else + { + if (true_regnum (operands[1])) + abort(); + operands[4] = operands[1]; + } +}) + + +(define_expand "divmodsi4" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (div:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (mod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))])] + "" + "") + +;; Allow to come the parameter in eax or edx to avoid extra moves. +;; Penalize eax case sligthly because it results in worse scheduling +;; of code. +(define_insn "*divmodsi4_nocltd" + [(set (match_operand:SI 0 "register_operand" "=&a,?a") + (div:SI (match_operand:SI 2 "register_operand" "1,0") + (match_operand:SI 3 "nonimmediate_operand" "rm,rm"))) + (set (match_operand:SI 1 "register_operand" "=&d,&d") + (mod:SI (match_dup 2) (match_dup 3))) + (clobber (reg:CC 17))] + "!optimize_size && !TARGET_USE_CLTD" + "#" + [(set_attr "type" "multi")]) + +(define_insn "*divmodsi4_cltd" + [(set (match_operand:SI 0 "register_operand" "=a") + (div:SI (match_operand:SI 2 "register_operand" "a") + (match_operand:SI 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SI 1 "register_operand" "=&d") + (mod:SI (match_dup 2) (match_dup 3))) + (clobber (reg:CC 17))] + "optimize_size || TARGET_USE_CLTD" + "#" + [(set_attr "type" "multi")]) + +(define_insn "*divmodsi_noext" [(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)))] + (set (match_operand:SI 3 "register_operand" "=d") + (mod:SI (match_dup 1) (match_dup 2))) + (use (match_operand:SI 4 "register_operand" "3")) + (clobber (reg:CC 17))] "" - "* -{ -#ifdef INTEL_SYNTAX - output_asm_insn (\"cdq\", operands); -#else - output_asm_insn (\"cltd\", operands); -#endif - return AS1 (idiv%L0,%2); -}" - [(set_attr "type" "idiv")]) + "idiv{l}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "few")]) +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (div:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (mod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "reload_completed" + [(parallel [(set (match_dup 3) + (ashiftrt:SI (match_dup 4) (const_int 31))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 0) + (div:SI (reg:SI 0) (match_dup 2))) + (set (match_dup 3) + (mod:SI (reg:SI 0) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))])] +{ + /* Avoid use of cltd in favour of a mov+shift. */ + if (!TARGET_USE_CLTD && !optimize_size) + { + if (true_regnum (operands[1])) + emit_move_insn (operands[0], operands[1]); + else + emit_move_insn (operands[3], operands[1]); + operands[4] = operands[3]; + } + else + { + if (true_regnum (operands[1])) + abort(); + operands[4] = operands[1]; + } +}) +;; %%% Split me. (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")]) + (mod:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "cwtd\;idiv{w}\t%2" + [(set_attr "type" "multi") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) + +(define_insn "udivmoddi4" + [(set (match_operand:DI 0 "register_operand" "=a") + (udiv:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:DI 3 "register_operand" "=&d") + (umod:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "xor{q}\t%3, %3\;div{q}\t%2" + [(set_attr "type" "multi") + (set_attr "length_immediate" "0") + (set_attr "mode" "DI")]) + +(define_insn "*udivmoddi4_noext" + [(set (match_operand:DI 0 "register_operand" "=a") + (udiv:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (set (match_operand:DI 3 "register_operand" "=d") + (umod:DI (match_dup 1) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "div{q}\t%2" + [(set_attr "type" "idiv") + (set_attr "ppro_uops" "few") + (set_attr "mode" "DI")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (udiv:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonimmediate_operand" ""))) + (set (match_operand:DI 3 "register_operand" "") + (umod:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 3) (const_int 0)) + (parallel [(set (match_dup 0) + (udiv:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (umod:DI (match_dup 1) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))])] + "") -;; ??? 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)))] + (umod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] "" - "* -{ - 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 + "xor{l}\t%3, %3\;div{l}\t%2" + [(set_attr "type" "multi") + (set_attr "length_immediate" "0") + (set_attr "mode" "SI")]) -(define_insn "" +(define_insn "*udivmodsi4_noext" [(set (match_operand:SI 0 "register_operand" "=a") - (udiv:DI (match_operand:DI 1 "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)))] + (umod:SI (match_dup 1) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))] "" - "div%L0 %2,%0" - [(set_attr "type" "idiv")]) -*/ - -;;- and instructions + "div{l}\t%2" + [(set_attr "type" "idiv") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) -;; 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]. +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (udiv:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonimmediate_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (umod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))] + "reload_completed" + [(set (match_dup 3) (const_int 0)) + (parallel [(set (match_dup 0) + (udiv:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (umod:SI (match_dup 1) (match_dup 2))) + (use (match_dup 3)) + (clobber (reg:CC 17))])] + "") -;; 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_expand "udivmodhi4" + [(set (match_dup 4) (const_int 0)) + (parallel [(set (match_operand:HI 0 "register_operand" "") + (udiv:HI (match_operand:HI 1 "register_operand" "") + (match_operand:HI 2 "nonimmediate_operand" ""))) + (set (match_operand:HI 3 "register_operand" "") + (umod:HI (match_dup 1) (match_dup 2))) + (use (match_dup 4)) + (clobber (reg:CC 17))])] + "TARGET_HIMODE_MATH" + "operands[4] = gen_reg_rtx (HImode);") + +(define_insn "*udivmodhi_noext" + [(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))) + (use (match_operand:HI 4 "register_operand" "3")) + (clobber (reg:CC 17))] + "" + "div{w}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "HI") + (set_attr "ppro_uops" "few")]) + +;; We can not use div/idiv for double division, because it causes +;; "division by zero" on the overflow and that's not what we expect +;; from truncate. Because true (non truncating) double division is +;; never generated, we can't create this insn anyway. +; +;(define_insn "" +; [(set (match_operand:SI 0 "register_operand" "=a") +; (truncate:SI +; (udiv:DI (match_operand:DI 1 "register_operand" "A") +; (zero_extend:DI +; (match_operand:SI 2 "nonimmediate_operand" "rm"))))) +; (set (match_operand:SI 3 "register_operand" "=d") +; (truncate:SI +; (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2))))) +; (clobber (reg:CC 17))] +; "" +; "div{l}\t{%2, %0|%0, %2}" +; [(set_attr "type" "idiv") +; (set_attr "ppro_uops" "few")]) + +;;- Logical AND instructions + +;; On Pentium, "test imm, reg" is pairable only with eax, ax, and al. +;; Note that this excludes ah. + +(define_insn "*testdi_1_rex64" + [(set (reg 17) + (compare + (and:DI (match_operand:DI 0 "nonimmediate_operand" "%*a,r,*a,r,rm") + (match_operand:DI 1 "x86_64_szext_nonmemory_operand" "Z,Z,e,e,re")) + (const_int 0)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "@ + test{l}\t{%k1, %k0|%k0, %k1} + test{l}\t{%k1, %k0|%k0, %k1} + test{q}\t{%1, %0|%0, %1} + test{q}\t{%1, %0|%0, %1} + test{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "test") + (set_attr "modrm" "0,1,0,1,1") + (set_attr "mode" "SI,SI,DI,DI,DI") + (set_attr "pent_pair" "uv,np,uv,np,uv")]) + +(define_insn "testsi_1" + [(set (reg 17) + (compare + (and:SI (match_operand:SI 0 "nonimmediate_operand" "%*a,r,rm") + (match_operand:SI 1 "nonmemory_operand" "in,in,rin")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode)" + "test{l}\t{%1, %0|%0, %1}" + [(set_attr "type" "test") + (set_attr "modrm" "0,1,1") + (set_attr "mode" "SI") + (set_attr "pent_pair" "uv,np,uv")]) + +(define_expand "testsi_ccno_1" + [(set (reg:CCNO 17) + (compare:CCNO + (and:SI (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "nonmemory_operand" "")) + (const_int 0)))] + "" + "") -(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")))] +(define_insn "*testhi_1" + [(set (reg 17) + (compare (and:HI (match_operand:HI 0 "nonimmediate_operand" "%*a,r,rm") + (match_operand:HI 1 "nonmemory_operand" "n,n,rn")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode)" + "test{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "test") + (set_attr "modrm" "0,1,1") + (set_attr "mode" "HI") + (set_attr "pent_pair" "uv,np,uv")]) + +(define_expand "testqi_ccz_1" + [(set (reg:CCZ 17) + (compare:CCZ (and:QI (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "nonmemory_operand" "")) + (const_int 0)))] "" - "* + "") + +(define_insn "*testqi_1" + [(set (reg 17) + (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm,r") + (match_operand:QI 1 "nonmemory_operand" "n,n,qn,n")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode)" { - HOST_WIDE_INT intval; - if (!rtx_equal_p (operands[0], operands[1]) - && rtx_equal_p (operands[0], operands[2])) + if (which_alternative == 3) { - rtx tmp; - tmp = operands[1]; - operands[1] = operands[2]; - operands[2] = tmp; + if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) & 0xffffff00)) + operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); + return "test{l}\t{%1, %k0|%k0, %1}"; } - 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; + return "test{b}\t{%1, %0|%0, %1}"; +} + [(set_attr "type" "test") + (set_attr "modrm" "0,1,1,1") + (set_attr "mode" "QI,QI,QI,SI") + (set_attr "pent_pair" "uv,np,uv,np")]) + +(define_expand "testqi_ext_ccno_0" + [(set (reg:CCNO 17) + (compare:CCNO + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (match_operand 1 "const_int_operand" "")) + (const_int 0)))] + "" + "") - operands[2] = GEN_INT (intval); +(define_insn "*testqi_ext_0" + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) + (match_operand 1 "const_int_operand" "n")) + (const_int 0)))] + "(unsigned HOST_WIDE_INT) INTVAL (operands[1]) <= 0xff + && ix86_match_ccmode (insn, CCNOmode)" + "test{b}\t{%1, %h0|%h0, %1}" + [(set_attr "type" "test") + (set_attr "mode" "QI") + (set_attr "length_immediate" "1") + (set_attr "pent_pair" "np")]) + +(define_insn "*testqi_ext_1" + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) + (zero_extend:SI + (match_operand:QI 1 "nonimmediate_operand" "Qm"))) + (const_int 0)))] + "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "test{b}\t{%1, %h0|%h0, %1}" + [(set_attr "type" "test") + (set_attr "mode" "QI")]) + +(define_insn "*testqi_ext_1_rex64" + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) + (zero_extend:SI + (match_operand:QI 1 "register_operand" "Q"))) + (const_int 0)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "test{b}\t{%1, %h0|%h0, %1}" + [(set_attr "type" "test") + (set_attr "mode" "QI")]) + +(define_insn "*testqi_ext_2" + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)) + (zero_extract:SI + (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8))) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode)" + "test{b}\t{%h1, %h0|%h0, %h1}" + [(set_attr "type" "test") + (set_attr "mode" "QI")]) + +;; Combine likes to form bit extractions for some tests. Humor it. +(define_insn "*testqi_ext_3" + [(set (reg 17) + (compare (zero_extract:SI + (match_operand 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_MODE (operands[0]) == SImode + || (TARGET_64BIT && GET_MODE (operands[0]) == DImode) + || GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == QImode)" + "#") - if (intval == 0) - return AS2 (mov%B0,%2,%b0); +(define_insn "*testqi_ext_3_rex64" + [(set (reg 17) + (compare (zero_extract:DI + (match_operand 0 "nonimmediate_operand" "rm") + (match_operand:DI 1 "const_int_operand" "") + (match_operand:DI 2 "const_int_operand" "")) + (const_int 0)))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCNOmode) + /* The code below cannot deal with constants outside HOST_WIDE_INT. */ + && INTVAL (operands[1]) + INTVAL (operands[2]) < HOST_BITS_PER_WIDE_INT + /* Ensure that resulting mask is zero or sign extended operand. */ + && (INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 + || (INTVAL (operands[1]) + INTVAL (operands[2]) == 64 + && INTVAL (operands[1]) > 32)) + && (GET_MODE (operands[0]) == SImode + || GET_MODE (operands[0]) == DImode + || GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == QImode)" + "#") - return AS2 (and%B0,%2,%b0); - } +(define_split + [(set (reg 17) + (compare (zero_extract + (match_operand 0 "nonimmediate_operand" "") + (match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" "")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode)" + [(set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))] +{ + HOST_WIDE_INT len = INTVAL (operands[1]); + HOST_WIDE_INT pos = INTVAL (operands[2]); + HOST_WIDE_INT mask; + enum machine_mode mode, submode; - /* only second byte has zero? */ - if (~(intval | 0xff00) == 0) + mode = GET_MODE (operands[0]); + if (GET_CODE (operands[0]) == MEM) + { + /* ??? Combine likes to put non-volatile mem extractions in QImode + no matter the size of the test. So find a mode that works. */ + if (! MEM_VOLATILE_P (operands[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); + mode = smallest_mode_for_size (pos + len, MODE_INT); + operands[0] = adjust_address (operands[0], mode, 0); } + } + else if (GET_CODE (operands[0]) == SUBREG + && (submode = GET_MODE (SUBREG_REG (operands[0])), + GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (submode)) + && pos + len <= GET_MODE_BITSIZE (submode)) + { + /* Narrow a paradoxical subreg to prevent partial register stalls. */ + mode = submode; + operands[0] = SUBREG_REG (operands[0]); + } + else if (mode == HImode && pos + len <= 8) + { + /* Small HImode tests can be converted to QImode. */ + mode = QImode; + operands[0] = gen_lowpart (QImode, operands[0]); + } - if (REG_P (operands[0])) - break; + mask = ((HOST_WIDE_INT)1 << (pos + len)) - 1; + mask &= ~(((HOST_WIDE_INT)1 << pos) - 1); - /* 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); - } + operands[3] = gen_rtx_AND (mode, operands[0], + GEN_INT (trunc_int_for_mode (mask, mode))); +}) - /* 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; - } +;; %%% This used to optimize known byte-wide and operations to memory, +;; and sometimes to QImode registers. If this is considered useful, +;; it should be done with splitters. - /* Low word is zero? */ - if (intval == 0xffff0000) - { -word_zero_and_operation: - CC_STATUS_INIT; - operands[2] = const0_rtx; - return AS2 (mov%W0,%2,%w0); - } +(define_expand "anddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "x86_64_szext_general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (AND, DImode, operands); DONE;") + +(define_insn "*anddi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r,r") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,qm") + (match_operand:DI 2 "x86_64_szext_general_operand" "Z,re,rm,L"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (AND, DImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_IMOVX: + { + enum machine_mode mode; - /* High word is zero? */ - if (intval == 0x0000ffff) - { - operands[0] = adj_offsettable_operand (operands[0], 2); - goto word_zero_and_operation; - } + if (GET_CODE (operands[2]) != CONST_INT) + abort (); + if (INTVAL (operands[2]) == 0xff) + mode = QImode; + else if (INTVAL (operands[2]) == 0xffff) + mode = HImode; + else + abort (); + + operands[1] = gen_lowpart (mode, operands[1]); + if (mode == QImode) + return "movz{bq|x}\t{%1,%0|%0, %1}"; + else + return "movz{wq|x}\t{%1,%0|%0, %1}"; + } default: - break; + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + if (get_attr_mode (insn) == MODE_SI) + return "and{l}\t{%k2, %k0|%k0, %k2}"; + else + return "and{q}\t{%2, %0|%0, %2}"; } +} + [(set_attr "type" "alu,alu,alu,imovx") + (set_attr "length_immediate" "*,*,*,0") + (set_attr "mode" "SI,DI,DI,DI")]) + +(define_insn "*anddi_2" + [(set (reg 17) + (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:DI 2 "x86_64_szext_general_operand" "Z,rem,re")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm") + (and:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, DImode, operands)" + "@ + and{l}\t{%k2, %k0|%k0, %k2} + and{q}\t{%2, %0|%0, %2} + and{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI,DI,DI")]) - 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")))] +(define_expand "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))] "" - "* + "ix86_expand_binary_operator (AND, SImode, operands); DONE;") + +(define_insn "*andsi_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,r") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,qm") + (match_operand:SI 2 "general_operand" "ri,rm,L"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (AND, SImode, operands)" { - if (GET_CODE (operands[2]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + switch (get_attr_type (insn)) { - /* Can we ignore the upper byte? */ - if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) - && (INTVAL (operands[2]) & 0xff00) == 0xff00) - { - CC_STATUS_INIT; + case TYPE_IMOVX: + { + enum machine_mode mode; - if ((INTVAL (operands[2]) & 0xff) == 0) - { - operands[2] = const0_rtx; - return AS2 (mov%B0,%2,%b0); - } + if (GET_CODE (operands[2]) != CONST_INT) + abort (); + if (INTVAL (operands[2]) == 0xff) + mode = QImode; + else if (INTVAL (operands[2]) == 0xffff) + mode = HImode; + else + abort (); + + operands[1] = gen_lowpart (mode, operands[1]); + if (mode == QImode) + return "movz{bl|x}\t{%1,%0|%0, %1}"; + else + return "movz{wl|x}\t{%1,%0|%0, %1}"; + } - operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); - return AS2 (and%B0,%2,%b0); - } + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); + return "and{l}\t{%2, %0|%0, %2}"; + } +} + [(set_attr "type" "alu,alu,imovx") + (set_attr "length_immediate" "*,*,0") + (set_attr "mode" "SI")]) - /* 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; +(define_split + [(set (match_operand 0 "register_operand" "") + (and (match_dup 0) + (const_int -65536))) + (clobber (reg:CC 17))] + "optimize_size" + [(set (strict_low_part (match_dup 1)) (const_int 0))] + "operands[1] = gen_lowpart (HImode, operands[0]);") - if ((INTVAL (operands[2]) & 0xff00) == 0) - { - operands[2] = const0_rtx; - return AS2 (mov%B0,%2,%h0); - } +(define_split + [(set (match_operand 0 "ext_register_operand" "") + (and (match_dup 0) + (const_int -256))) + (clobber (reg:CC 17))] + "(optimize_size || !TARGET_PARTIAL_REG_STALL) && reload_completed" + [(set (strict_low_part (match_dup 1)) (const_int 0))] + "operands[1] = gen_lowpart (QImode, operands[0]);") - operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); - return AS2 (and%B0,%2,%h0); - } +(define_split + [(set (match_operand 0 "ext_register_operand" "") + (and (match_dup 0) + (const_int -65281))) + (clobber (reg:CC 17))] + "(optimize_size || !TARGET_PARTIAL_REG_STALL) && reload_completed" + [(parallel [(set (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)) + (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)))) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (SImode, operands[0]);") + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*andsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (AND, SImode, operands)" + "and{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*andsi_2" + [(set (reg 17) + (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") + (and:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, SImode, operands)" + "and{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*andsi_2_zext" + [(set (reg 17) + (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (and:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, SImode, operands)" + "and{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_expand "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (and:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (AND, HImode, operands); DONE;") + +(define_insn "*andhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") + (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,qm") + (match_operand:HI 2 "general_operand" "ri,rm,L"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (AND, HImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_IMOVX: + if (GET_CODE (operands[2]) != CONST_INT) + abort (); + if (INTVAL (operands[2]) == 0xff) + return "movz{bl|x}\t{%b1, %k0|%k0, %b1}"; + abort (); - /* 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); - } - } + default: + if (! rtx_equal_p (operands[0], operands[1])) + abort (); - 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); + return "and{w}\t{%2, %0|%0, %2}"; } +} + [(set_attr "type" "alu,alu,imovx") + (set_attr "length_immediate" "*,*,0") + (set_attr "mode" "HI,HI,SI")]) + +(define_insn "*andhi_2" + [(set (reg 17) + (compare (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (and:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, HImode, operands)" + "and{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_expand "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (and:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (AND, QImode, operands); DONE;") + +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*andqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") + (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qi,qmi,ri"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (AND, QImode, operands)" + "@ + and{b}\t{%2, %0|%0, %2} + and{b}\t{%2, %0|%0, %2} + and{l}\t{%k2, %k0|%k0, %k2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI,QI,SI")]) - /* Use a 32-bit word with the upper bits set, invalidate CC */ - if (GET_CODE (operands[2]) == CONST_INT - && i386_aligned_p (operands[0])) +(define_insn "*andqi_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) + (and:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "qi,qmi"))) + (clobber (reg:CC 17))] + "" + "and{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +(define_insn "*andqi_2" + [(set (reg 17) + (compare (and:QI + (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qim,qi,i")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r") + (and:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, QImode, operands)" +{ + if (which_alternative == 2) { - 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); + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 0xffffff00)) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); + return "and{l}\t{%2, %k0|%k0, %2}"; } - - 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") + return "and{b}\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "alu") + (set_attr "mode" "QI,QI,SI")]) + +(define_insn "*andqi_2_slp" + [(set (reg 17) + (compare (and:QI + (match_operand:QI 0 "nonimmediate_operand" "+q,qm") + (match_operand:QI 1 "nonimmediate_operand" "qmi,qi")) + (const_int 0))) + (set (strict_low_part (match_dup 0)) + (and:QI (match_dup 0) (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode)" + "and{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +;; ??? A bug in recog prevents it from recognizing a const_int as an +;; operand to zero_extend in andqi_ext_1. It was checking explicitly +;; for a QImode operand, which of course failed. + +(define_insn "andqi_ext_0" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand 2 "const_int_operand" "n"))) + (clobber (reg:CC 17))] + "(unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff" + "and{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "1") + (set_attr "mode" "QI")]) + +;; Generated by peephole translating test to and. This shows up +;; often in fp comparisons. + +(define_insn "*andqi_ext_0_cc" + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand 2 "const_int_operand" "n")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI + (match_dup 1) + (const_int 8) + (const_int 8)) + (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && (unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff" + "and{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "1") + (set_attr "mode" "QI")]) + +(define_insn "*andqi_ext_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (zero_extend:SI + (match_operand:QI 2 "general_operand" "Qm")))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "and{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) + +(define_insn "*andqi_ext_1_rex64" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (zero_extend:SI + (match_operand 2 "ext_register_operand" "Q")))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "and{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) + +(define_insn "*andqi_ext_2" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) (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") - -*/ + (zero_extract:SI + (match_operand 1 "ext_register_operand" "%0") + (const_int 8) + (const_int 8)) + (zero_extract:SI + (match_operand 2 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))) + (clobber (reg:CC 17))] + "" + "and{b}\t{%h2, %h0|%h0, %h2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) -;;- Bit set (inclusive or) instructions +;; Logical 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" +;; %%% This used to optimize known byte-wide and operations to memory. +;; If this is considered useful, it should be done with splitters. + +(define_expand "iordi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (ior:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "x86_64_general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (IOR, DImode, operands); DONE;") + +(define_insn "*iordi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rme"))) + (clobber (reg:CC 17))] + "TARGET_64BIT + && ix86_binary_operator_ok (IOR, DImode, operands)" + "or{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*iordi_2_rex64" + [(set (reg 17) + (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "rem,re")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") + (ior:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, DImode, operands)" + "or{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_insn "*iordi_3_rex64" + [(set (reg 17) + (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "x86_64_general_operand" "rem")) + (const_int 0))) + (clobber (match_scratch:DI 0 "=r"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, DImode, operands)" + "or{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (IOR, SImode, operands); DONE;") + +(define_insn "*iorsi_1" [(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")))] + (match_operand:SI 2 "general_operand" "ri,rmi"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (IOR, SImode, operands)" + "or{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*iorsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=rm") + (zero_extend:DI + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (IOR, SImode, operands)" + "or{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi_1_zext_imm" + [(set (match_operand:DI 0 "register_operand" "=rm") + (ior:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "or{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi_2" + [(set (reg 17) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") + (ior:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, SImode, operands)" + "or{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +;; ??? Special case for immediate operand is missing - it is tricky. +(define_insn "*iorsi_2_zext" + [(set (reg 17) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ior:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, SImode, operands)" + "or{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi_2_zext_imm" + [(set (reg 17) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand 2 "x86_64_zext_immediate_operand" "Z")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (ior:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, SImode, operands)" + "or{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*iorsi_3" + [(set (reg 17) + (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "or{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_expand "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ior:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (IOR, HImode, operands); DONE;") + +(define_insn "*iorhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") + (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rmi,ri"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (IOR, HImode, operands)" + "or{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*iorhi_2" + [(set (reg 17) + (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (ior:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, HImode, operands)" + "or{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*iorhi_3" + [(set (reg 17) + (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0") + (match_operand:HI 2 "general_operand" "rim")) + (const_int 0))) + (clobber (match_scratch:HI 0 "=r"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "or{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_expand "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ior:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (IOR, QImode, operands); DONE;") + +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*iorqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") + (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qmi,qi,ri"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (IOR, QImode, operands)" + "@ + or{b}\t{%2, %0|%0, %2} + or{b}\t{%2, %0|%0, %2} + or{l}\t{%k2, %k0|%k0, %k2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI,QI,SI")]) + +(define_insn "*iorqi_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m")) + (ior:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "qmi,qi"))) + (clobber (reg:CC 17))] "" - "* -{ - HOST_WIDE_INT intval; - switch (GET_CODE (operands[2])) - { - case CONST_INT: + "or{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +(define_insn "*iorqi_2" + [(set (reg 17) + (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qim,qi")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") + (ior:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (IOR, QImode, operands)" + "or{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*iorqi_2_slp" + [(set (reg 17) + (compare (ior:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") + (match_operand:QI 1 "general_operand" "qim,qi")) + (const_int 0))) + (set (strict_low_part (match_dup 0)) + (ior:QI (match_dup 0) (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode)" + "or{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +(define_insn "*iorqi_3" + [(set (reg 17) + (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0") + (match_operand:QI 2 "general_operand" "qim")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=q"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "or{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) - 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; + +;; Logical XOR instructions - 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; - } +;; %%% This used to optimize known byte-wide and operations to memory. +;; If this is considered useful, it should be done with splitters. -byte_or_operation: - CC_STATUS_INIT; +(define_expand "xordi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (xor:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "x86_64_general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (XOR, DImode, operands); DONE;") + +(define_insn "*xordi_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) + (clobber (reg:CC 17))] + "TARGET_64BIT + && ix86_binary_operator_ok (XOR, DImode, operands)" + "@ + xor{q}\t{%2, %0|%0, %2} + xor{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI,DI")]) + +(define_insn "*xordi_2_rex64" + [(set (reg 17) + (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") + (match_operand:DI 2 "x86_64_general_operand" "rem,re")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") + (xor:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, DImode, operands)" + "@ + xor{q}\t{%2, %0|%0, %2} + xor{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI,DI")]) + +(define_insn "*xordi_3_rex64" + [(set (reg 17) + (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "x86_64_general_operand" "rem")) + (const_int 0))) + (clobber (match_scratch:DI 0 "=r"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, DImode, operands)" + "xor{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "DI")]) + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (XOR, SImode, operands); DONE;") - if (intval != INTVAL (operands[2])) - operands[2] = GEN_INT (intval); +(define_insn "*xorsi_1" + [(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"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +;; Add speccase for immediates +(define_insn "*xorsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi_1_zext_imm" + [(set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi_2" + [(set (reg 17) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") + (xor:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +;; ??? Special case for immediate operand is missing - it is tricky. +(define_insn "*xorsi_2_zext" + [(set (reg 17) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (xor:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi_2_zext_imm" + [(set (reg 17) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand 2 "x86_64_zext_immediate_operand" "Z")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (xor:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, SImode, operands)" + "xor{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_insn "*xorsi_3" + [(set (reg 17) + (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rim")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=r"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "xor{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + +(define_expand "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (xor:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (XOR, HImode, operands); DONE;") + +(define_insn "*xorhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") + (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rmi,ri"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (XOR, HImode, operands)" + "xor{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*xorhi_2" + [(set (reg 17) + (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rim,ri")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (xor:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, HImode, operands)" + "xor{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_insn "*xorhi_3" + [(set (reg 17) + (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0") + (match_operand:HI 2 "general_operand" "rim")) + (const_int 0))) + (clobber (match_scratch:HI 0 "=r"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "xor{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "HI")]) + +(define_expand "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (XOR, QImode, operands); DONE;") + +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*xorqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qmi,qi,ri"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (XOR, QImode, operands)" + "@ + xor{b}\t{%2, %0|%0, %2} + xor{b}\t{%2, %0|%0, %2} + xor{l}\t{%k2, %k0|%k0, %k2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI,QI,SI")]) + +(define_insn "*xorqi_ext_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (zero_extract:SI (match_operand 2 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))) + (clobber (reg:CC 17))] + "" + "xor{b}\t{%h2, %h0|%h0, %h2}" + [(set_attr "type" "alu") + (set_attr "length_immediate" "0") + (set_attr "mode" "QI")]) + +(define_insn "*xorqi_cc_1" + [(set (reg 17) + (compare + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qim,qi")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") + (xor:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (XOR, QImode, operands)" + "xor{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*xorqi_cc_2" + [(set (reg 17) + (compare + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0") + (match_operand:QI 2 "general_operand" "qim")) + (const_int 0))) + (clobber (match_scratch:QI 0 "=q"))] + "ix86_match_ccmode (insn, CCNOmode) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "xor{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*xorqi_cc_ext_1" + [(set (reg 17) + (compare + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "qmn")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) + (match_dup 2)))] + "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "xor{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_insn "*xorqi_cc_ext_1_rex64" + [(set (reg 17) + (compare + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "nonmemory_operand" "Qn")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) + (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "xor{b}\t{%2, %h0|%h0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "QI")]) + +(define_expand "xorqi_cc_ext_1" + [(parallel [ + (set (reg:CCNO 17) + (compare:CCNO + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) + (match_dup 2)))])] + "" + "") + +;; Negation instructions - if (intval == 0xff) - return AS2 (mov%B0,%2,%b0); +(define_expand "negdi2" + [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "") + (neg:DI (match_operand:DI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "" + "ix86_expand_unary_operator (NEG, DImode, operands); DONE;") + +(define_insn "*negdi2_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=ro") + (neg:DI (match_operand:DI 1 "general_operand" "0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT + && ix86_unary_operator_ok (NEG, DImode, operands)" + "#") - return AS2 (or%B0,%2,%b0); - } +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (neg:DI (match_operand:DI 1 "general_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(parallel + [(set (reg:CCZ 17) + (compare:CCZ (neg:SI (match_dup 2)) (const_int 0))) + (set (match_dup 0) (neg:SI (match_dup 2)))]) + (parallel + [(set (match_dup 1) + (plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0)) + (match_dup 3)) + (const_int 0))) + (clobber (reg:CC 17))]) + (parallel + [(set (match_dup 1) + (neg:SI (match_dup 1))) + (clobber (reg:CC 17))])] + "split_di (operands+1, 1, operands+2, operands+3); + split_di (operands+0, 1, operands+0, operands+1);") + +(define_insn "*negdi2_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" + "neg{q}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "DI")]) + +;; The problem with neg is that it does not perform (compare x 0), +;; it really performs (compare 0 x), which leaves us with the zero +;; flag being the only useful item. + +(define_insn "*negdi2_cmpz_rex64" + [(set (reg:CCZ 17) + (compare:CCZ (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (neg:DI (match_dup 1)))] + "TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" + "neg{q}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "DI")]) + + +(define_expand "negsi2" + [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "" + "ix86_expand_unary_operator (NEG, SImode, operands); DONE;") - /* second byte? */ - if ((intval & ~0xff00) == 0) +(define_insn "*negsi2_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +;; Combine is quite creative about this pattern. +(define_insn "*negsi2_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (neg:DI (ashift:DI (match_operand:DI 1 "register_operand" "0") + (const_int 32))) + (const_int 32))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%k0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +;; The problem with neg is that it does not perform (compare x 0), +;; it really performs (compare 0 x), which leaves us with the zero +;; flag being the only useful item. + +(define_insn "*negsi2_cmpz" + [(set (reg:CCZ 17) + (compare:CCZ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (neg:SI (match_dup 1)))] + "ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +(define_insn "*negsi2_cmpz_zext" + [(set (reg:CCZ 17) + (compare:CCZ (lshiftrt:DI + (neg:DI (ashift:DI + (match_operand:DI 1 "register_operand" "0") + (const_int 32))) + (const_int 32)) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (neg:DI (ashift:DI (match_dup 1) + (const_int 32))) + (const_int 32)))] + "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%k0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +(define_expand "neghi2" + [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "") + (neg:HI (match_operand:HI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_HIMODE_MATH" + "ix86_expand_unary_operator (NEG, HImode, operands); DONE;") + +(define_insn "*neghi2_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, HImode, operands)" + "neg{w}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "HI")]) + +(define_insn "*neghi2_cmpz" + [(set (reg:CCZ 17) + (compare:CCZ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (neg:HI (match_dup 1)))] + "ix86_unary_operator_ok (NEG, HImode, operands)" + "neg{w}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "HI")]) + +(define_expand "negqi2" + [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "") + (neg:QI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_QIMODE_MATH" + "ix86_expand_unary_operator (NEG, QImode, operands); DONE;") + +(define_insn "*negqi2_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, QImode, operands)" + "neg{b}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "QI")]) + +(define_insn "*negqi2_cmpz" + [(set (reg:CCZ 17) + (compare:CCZ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (neg:QI (match_dup 1)))] + "ix86_unary_operator_ok (NEG, QImode, operands)" + "neg{b}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "QI")]) + +;; Changing of sign for FP values is doable using integer unit too. + +(define_expand "negsf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387" + "if (TARGET_SSE) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_negsf2_memory (operands[0], operands[1])); + else { - 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; + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (SFmode); + rtx dest = operands[0]; + + operands[1] = force_reg (SFmode, operands[1]); + operands[0] = force_reg (SFmode, operands[0]); + emit_move_insn (reg, + gen_lowpart (SFmode, + GEN_INT (trunc_int_for_mode (0x80000000, + SImode)))); + emit_insn (gen_negsf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); } + DONE; + } + ix86_expand_unary_operator (NEG, SFmode, operands); DONE;") - 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; - } +(define_insn "negsf2_memory" + [(set (match_operand:SF 0 "memory_operand" "=m") + (neg:SF (match_operand:SF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, SFmode, operands)" + "#") - /* fourth byte? */ - if ((intval & ~0xff000000) == 0) - { - intval = (intval >> 24) & 0xff; - operands[0] = adj_offsettable_operand (operands[0], 3); - goto byte_or_operation; - } +(define_insn "negsf2_ifs" + [(set (match_operand:SF 0 "nonimmediate_operand" "=x#fr,x#fr,f#xr,rm#xf") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,x#fr,0,0"))) + (use (match_operand:SF 2 "nonmemory_operand" "x,0#x,*g#x,*g#x")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") - default: - break; - } +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (neg:SF (match_operand:SF 1 "memory_operand" ""))) + (use (match_operand:SF 2 "" "")) + (clobber (reg:CC 17))] + "" + [(parallel [(set (match_dup 0) + (neg:SF (match_dup 1))) + (clobber (reg:CC 17))])]) - return AS2 (or%L0,%2,%0); -}" - [(set_attr "type" "binary")]) +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:SF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (neg:SF (match_dup 1))) + (clobber (reg:CC 17))])]) -(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")))] - "" - "* +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:SF 2 "register_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (subreg:TI (match_dup 0) 0) + (xor:TI (subreg:TI (match_dup 1) 0) + (subreg:TI (match_dup 2) 0)))] { - HOST_WIDE_INT intval; - switch (GET_CODE (operands[2])) + if (operands_match_p (operands[0], 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]); + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } +}) + + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negsf2_if" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 && !TARGET_SSE + && ix86_unary_operator_ok (NEG, SFmode, operands)" + "#") - 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; - } +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (neg:SF (match_dup 1)))] + "") -byte_or_operation: - CC_STATUS_INIT; +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (trunc_int_for_mode (0x80000000, SImode)); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));") - if (intval == 0xff) - return AS2 (mov%B0,%2,%b0); +(define_split + [(set (match_operand 0 "memory_operand" "") + (neg (match_operand 1 "memory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(parallel [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] +{ + int size = GET_MODE_SIZE (GET_MODE (operands[1])); - return AS2 (or%B0,%2,%b0); - } + /* XFmode's size is 12, TFmode 16, but only 10 bytes are used. */ + if (size >= 12) + size = 10; + operands[0] = adjust_address (operands[0], QImode, size - 1); + operands[1] = GEN_INT (trunc_int_for_mode (0x80, QImode)); +}) - /* high byte? */ - if ((intval & 0xff) == 0) +(define_expand "negdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387" + "if (TARGET_SSE2) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_negdf2_memory (operands[0], operands[1])); + else { - 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; + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (DFmode); +#if HOST_BITS_PER_WIDE_INT >= 64 + rtx imm = GEN_INT (trunc_int_for_mode(((HOST_WIDE_INT)1) << 63, + DImode)); +#else + rtx imm = immed_double_const (0, 0x80000000, DImode); +#endif + rtx dest = operands[0]; + + operands[1] = force_reg (DFmode, operands[1]); + operands[0] = force_reg (DFmode, operands[0]); + emit_move_insn (reg, gen_lowpart (DFmode, imm)); + emit_insn (gen_negdf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); } + DONE; + } + ix86_expand_unary_operator (NEG, DFmode, operands); DONE;") - 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); - } +(define_insn "negdf2_memory" + [(set (match_operand:DF 0 "memory_operand" "=m") + (neg:DF (match_operand:DF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (NEG, DFmode, operands)" + "#") - 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); - } +(define_insn "negdf2_ifs" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,Y#fr,f#Yr,rm#Yf") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0,0"))) + (use (match_operand:DF 2 "nonmemory_operand" "Y,0,*g#Y,*g#Y")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") - return AS2 (or%W0,%2,%0); -}" - [(set_attr "type" "binary")]) +(define_insn "*negdf2_ifs_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,Y#fr,fm#Yr,r#Yf") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,Y#fr,0,0"))) + (use (match_operand:DF 2 "general_operand" "Y,0,*g#Yr,*rm")) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") -(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")))] +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (neg:DF (match_operand:DF 1 "memory_operand" ""))) + (use (match_operand:DF 2 "" "")) + (clobber (reg:CC 17))] "" - "* return AS2 (or%B0,%2,%0);" - [(set_attr "type" "binary")]) - -;;- xor instructions + [(parallel [(set (match_dup 0) + (neg:DF (match_dup 1))) + (clobber (reg:CC 17))])]) -(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")))] - "" - "* +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:DF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0]) + && (!TARGET_64BIT || FP_REG_P (operands[0]))" + [(parallel [(set (match_dup 0) + (neg:DF (match_dup 1))) + (clobber (reg:CC 17))])]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:DF 2 "" "")) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed && GENERAL_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (xor:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, operands[1]); + operands[2] = gen_lowpart (DImode, operands[2]);") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:DF 2 "register_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (subreg:TI (match_dup 0) 0) + (xor:TI (subreg:TI (match_dup 1) 0) + (subreg:TI (match_dup 2) 0)))] { - HOST_WIDE_INT intval; - switch (GET_CODE (operands[2])) + if (operands_match_p (operands[0], operands[2])) { - case CONST_INT: - - if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) - break; + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } +}) + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negdf2_if" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (NEG, DFmode, operands)" + "#") - /* don't try to optimize volatile accesses */ - if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) - break; +;; FIXME: We should to allow integer registers here. Problem is that +;; we need another scratch register to get constant from. +;; Forcing constant to mem if no register available in peep2 should be +;; safe even for PIC mode, because of RIP relative addressing. +(define_insn "*negdf2_if_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,mf") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (NEG, DFmode, operands)" + "#") - 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); - } +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (neg:DF (match_dup 1)))] + "") - /* second byte? */ - if ((intval & ~0xff00) == 0) - { - intval >>= 8; +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 && reload_completed + && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 3) (xor:SI (match_dup 3) (match_dup 4))) + (clobber (reg:CC 17))])] + "operands[4] = GEN_INT (trunc_int_for_mode (0x80000000, SImode)); + split_di (operands+0, 1, operands+2, operands+3);") + +(define_expand "negxf2" + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "!TARGET_64BIT && TARGET_80387" + "ix86_expand_unary_operator (NEG, XFmode, operands); DONE;") + +(define_expand "negtf2" + [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "") + (neg:TF (match_operand:TF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387" + "ix86_expand_unary_operator (NEG, TFmode, operands); DONE;") + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negxf2_if" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (NEG, XFmode, operands)" + "#") - 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); +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (neg:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (neg:XF (match_dup 1)))] + "") - operands[2] = GEN_INT (intval); - return AS2 (xor%B0,%2,%h0); - } +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (neg:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*negtf2_if" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,rm#f") + (neg:TF (match_operand:TF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 && ix86_unary_operator_ok (NEG, TFmode, operands)" + "#") - operands[0] = adj_offsettable_operand (operands[0], 1); +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (neg:TF (match_operand:TF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (neg:TF (match_dup 1)))] + "") - goto byte_xor_operation; - } +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (neg:TF (match_operand:TF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") + +;; Conditionize these after reload. If they matches before reload, we +;; lose the clobber and ability to use integer instructions. + +(define_insn "*negsf2_1" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "SF") + (set_attr "ppro_uops" "few")]) - if (REG_P (operands[0])) - break; +(define_insn "*negdf2_1" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "DF") + (set_attr "ppro_uops" "few")]) - /* third byte? */ - if ((intval & ~0xff0000) == 0) - { - intval >>= 16; - operands[0] = adj_offsettable_operand (operands[0], 2); - goto byte_xor_operation; - } +(define_insn "*negextendsfdf2" + [(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" "fsgn") + (set_attr "mode" "DF") + (set_attr "ppro_uops" "few")]) - /* fourth byte? */ - if ((intval & ~0xff000000) == 0) - { - intval = (intval >> 24) & 0xff; - operands[0] = adj_offsettable_operand (operands[0], 3); - goto byte_xor_operation; - } +(define_insn "*negxf2_1" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (match_operand:XF 1 "register_operand" "0")))] + "!TARGET_64BIT && TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) - default: - break; - } +(define_insn "*negextenddfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) - return AS2 (xor%L0,%2,%0); -}" - [(set_attr "type" "binary")]) +(define_insn "*negextendsfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) -(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); +(define_insn "*negtf2_1" + [(set (match_operand:TF 0 "register_operand" "=f") + (neg:TF (match_operand:TF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) - 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); +(define_insn "*negextenddftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (neg:TF (float_extend:TF + (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) - return AS2 (xor%B0,%2,%b0); - } +(define_insn "*negextendsftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (neg:TF (float_extend:TF + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "fchs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF") + (set_attr "ppro_uops" "few")]) + +;; Absolute value instructions - /* Can we ignore the lower byte? */ - /* ??? what about offsettable memory references? */ - if (QI_REG_P (operands[0]) - && (INTVAL (operands[2]) & 0xff) == 0) +(define_expand "abssf2" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387" + "if (TARGET_SSE) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_abssf2_memory (operands[0], operands[1])); + else { - 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); + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (SFmode); + rtx dest = operands[0]; + + operands[1] = force_reg (SFmode, operands[1]); + operands[0] = force_reg (SFmode, operands[0]); + emit_move_insn (reg, + gen_lowpart (SFmode, + GEN_INT (trunc_int_for_mode (0x80000000, + SImode)))); + emit_insn (gen_abssf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); } - } - - 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); - } + DONE; + } + ix86_expand_unary_operator (ABS, SFmode, operands); DONE;") - 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); - } +(define_insn "abssf2_memory" + [(set (match_operand:SF 0 "memory_operand" "=m") + (abs:SF (match_operand:SF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (ABS, SFmode, operands)" + "#") - return AS2 (xor%W0,%2,%0); -}" - [(set_attr "type" "binary")]) +(define_insn "abssf2_ifs" + [(set (match_operand:SF 0 "nonimmediate_operand" "=x#fr,f#xr,rm#xf") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "x,0,0"))) + (use (match_operand:SF 2 "nonmemory_operand" "*0#x,*g#x,*g#x")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") -(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")))] +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (abs:SF (match_operand:SF 1 "memory_operand" ""))) + (use (match_operand:SF 2 "" "")) + (clobber (reg:CC 17))] "" - "* return AS2 (xor%B0,%2,%0);" - [(set_attr "type" "binary")]) - -;; logical operations for DImode + [(parallel [(set (match_dup 0) + (abs:SF (match_dup 1))) + (clobber (reg:CC 17))])]) -(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_split + [(set (match_operand:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:SF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (abs:SF (match_dup 1))) + (clobber (reg:CC 17))])]) +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (use (match_operand:SF 2 "register_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (subreg:TI (match_dup 0) 0) + (and:TI (not:TI (subreg:TI (match_dup 2) 0)) + (subreg:TI (match_dup 1) 0)))]) + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*abssf2_if" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 && ix86_unary_operator_ok (ABS, SFmode, operands) && !TARGET_SSE" + "#") -(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_split + [(set (match_operand:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0]))" + [(set (match_dup 0) + (abs:SF (match_dup 1)))] + "") -(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:SF 0 "register_operand" "") + (abs:SF (match_operand:SF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (trunc_int_for_mode (~0x80000000, SImode)); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));") (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]);") + [(set (match_operand 0 "memory_operand" "") + (abs (match_operand 1 "memory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(parallel [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] +{ + int size = GET_MODE_SIZE (GET_MODE (operands[1])); -;;- negation instructions + /* XFmode's size is 12, TFmode 16, but only 10 bytes are used. */ + if (size >= 12) + size = 10; + operands[0] = adjust_address (operands[0], QImode, size - 1); + operands[1] = GEN_INT (trunc_int_for_mode (~0x80, QImode)); +}) -(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]; +(define_expand "absdf2" + [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "") + (neg:DF (match_operand:DF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "TARGET_80387" + "if (TARGET_SSE2) + { + /* In case operand is in memory, we will not use SSE. */ + if (memory_operand (operands[0], VOIDmode) + && rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_absdf2_memory (operands[0], operands[1])); + else + { + /* Using SSE is tricky, since we need bitwise negation of -0 + in register. */ + rtx reg = gen_reg_rtx (DFmode); +#if HOST_BITS_PER_WIDE_INT >= 64 + rtx imm = GEN_INT (trunc_int_for_mode(((HOST_WIDE_INT)1) << 63, + DImode)); +#else + rtx imm = immed_double_const (0, 0x80000000, DImode); +#endif + rtx dest = operands[0]; + + operands[1] = force_reg (DFmode, operands[1]); + operands[0] = force_reg (DFmode, operands[0]); + emit_move_insn (reg, gen_lowpart (DFmode, imm)); + emit_insn (gen_absdf2_ifs (operands[0], operands[1], reg)); + if (dest != operands[0]) + emit_move_insn (dest, operands[0]); + } + DONE; + } + ix86_expand_unary_operator (ABS, DFmode, operands); DONE;") - CC_STATUS_INIT; +(define_insn "absdf2_memory" + [(set (match_operand:DF 0 "memory_operand" "=m") + (abs:DF (match_operand:DF 1 "memory_operand" "0"))) + (clobber (reg:CC 17))] + "ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") - split_di (operands, 1, low, high); - xops[0] = const0_rtx; - xops[1] = high[0]; +(define_insn "absdf2_ifs" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,mf#Yr,mr#Yf") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "Y,0,0"))) + (use (match_operand:DF 2 "nonmemory_operand" "*0#Y,*g#Y,*g#Y")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") - 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 "*absdf2_ifs_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y#fr,mf#Yr") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "Y,0"))) + (use (match_operand:DF 2 "nonmemory_operand" "*0#Y,*g#Y")) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_SSE2 + && (reload_in_progress || reload_completed + || (register_operand (operands[0], VOIDmode) + && register_operand (operands[1], VOIDmode)))" + "#") -(define_insn "negsi2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (abs:DF (match_operand:DF 1 "memory_operand" ""))) + (use (match_operand:DF 2 "" "")) + (clobber (reg:CC 17))] "" - "neg%L0 %0") + [(parallel [(set (match_dup 0) + (abs:DF (match_dup 1))) + (clobber (reg:CC 17))])]) -(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_split + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:DF 2 "" "")) + (clobber (reg:CC 17))] + "reload_completed && !SSE_REG_P (operands[0])" + [(parallel [(set (match_dup 0) + (abs:DF (match_dup 1))) + (clobber (reg:CC 17))])]) -(define_insn "negqi2" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))] - "" - "neg%B0 %0") +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (use (match_operand:DF 2 "register_operand" "")) + (clobber (reg:CC 17))] + "reload_completed && SSE_REG_P (operands[0])" + [(set (subreg:TI (match_dup 0) 0) + (and:TI (not:TI (subreg:TI (match_dup 2) 0)) + (subreg:TI (match_dup 1) 0)))]) + + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*absdf2_if" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") -(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")]) +;; FIXME: We should to allow integer registers here. Problem is that +;; we need another scratch register to get constant from. +;; Forcing constant to mem if no register available in peep2 should be +;; safe even for PIC mode, because of RIP relative addressing. +(define_insn "*absdf2_if_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,mf") + (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (ABS, DFmode, operands)" + "#") -(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_split + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (abs:DF (match_dup 1)))] + "") -(define_insn "" - [(set (match_operand:DF 0 "register_operand" "=f") - (neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (abs:DF (match_operand:DF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 && reload_completed && + !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 3) (and:SI (match_dup 3) (match_dup 4))) + (clobber (reg:CC 17))])] + "operands[4] = GEN_INT (trunc_int_for_mode (~0x80000000, SImode)); + split_di (operands+0, 1, operands+2, operands+3);") + +(define_expand "absxf2" + [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "") + (neg:XF (match_operand:XF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] + "!TARGET_64BIT && TARGET_80387" + "ix86_expand_unary_operator (ABS, XFmode, operands); DONE;") + +(define_expand "abstf2" + [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "") + (neg:TF (match_operand:TF 1 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))])] "TARGET_80387" - "fchs" - [(set_attr "type" "fpop")]) + "ix86_expand_unary_operator (ABS, TFmode, operands); DONE;") + +;; Keep 'f' and 'r' in separate alternatives to avoid reload problems +;; because of secondary memory needed to reload from class FLOAT_INT_REGS +;; to itself. +(define_insn "*absxf2_if" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:XF (match_operand:XF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_80387 + && ix86_unary_operator_ok (ABS, XFmode, operands)" + "#") -(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_split + [(set (match_operand:XF 0 "register_operand" "") + (abs:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (abs:XF (match_dup 1)))] + "") -(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_split + [(set (match_operand:XF 0 "register_operand" "") + (abs:XF (match_operand:XF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (~0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") + +(define_insn "*abstf2_if" + [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,rm#f") + (abs:TF (match_operand:TF 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC 17))] + "TARGET_80387 && ix86_unary_operator_ok (ABS, TFmode, operands)" + "#") -(define_insn "abssf2" +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (abs:TF (match_operand:TF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed" + [(set (match_dup 0) + (abs:TF (match_dup 1)))] + "") + +(define_split + [(set (match_operand:TF 0 "register_operand" "") + (abs:TF (match_operand:TF 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[1] = GEN_INT (~0x8000); + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + (TARGET_64BIT ? 1 : 2));") + +(define_insn "*abssf2_1" [(set (match_operand:SF 0 "register_operand" "=f") (abs:SF (match_operand:SF 1 "register_operand" "0")))] - "TARGET_80387" + "TARGET_80387 && reload_completed" "fabs" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fsgn") + (set_attr "mode" "SF")]) -(define_insn "absdf2" +(define_insn "*absdf2_1" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "register_operand" "0")))] - "TARGET_80387" + "TARGET_80387 && reload_completed" "fabs" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fsgn") + (set_attr "mode" "DF")]) -(define_insn "" +(define_insn "*absextendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") - (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] + (abs:DF (float_extend:DF + (match_operand:SF 1 "register_operand" "0"))))] "TARGET_80387" "fabs" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fsgn") + (set_attr "mode" "DF")]) -(define_insn "absxf2" +(define_insn "*absxf2_1" [(set (match_operand:XF 0 "register_operand" "=f") (abs:XF (match_operand:XF 1 "register_operand" "0")))] - "TARGET_80387" + "!TARGET_64BIT && TARGET_80387 && reload_completed" "fabs" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fsgn") + (set_attr "mode" "DF")]) -(define_insn "" +(define_insn "*absextenddfxf2" [(set (match_operand:XF 0 "register_operand" "=f") - (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))] - "TARGET_80387" + (abs:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387" "fabs" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) -(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" +(define_insn "*absextendsfxf2" [(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") + (abs:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387" + "fabs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) -(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 "*abstf2_1" + [(set (match_operand:TF 0 "register_operand" "=f") + (abs:TF (match_operand:TF 1 "register_operand" "0")))] + "TARGET_80387 && reload_completed" + "fabs" + [(set_attr "type" "fsgn") + (set_attr "mode" "DF")]) -(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 "*absextenddftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (abs:TF (float_extend:TF + (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) -(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 "*absextendsftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (abs:TF (float_extend:TF + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "fabs" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) + +;; One complement instructions -(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_expand "one_cmpldi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (not:DI (match_operand:DI 1 "nonimmediate_operand" "")))] + "TARGET_64BIT" + "ix86_expand_unary_operator (NOT, DImode, operands); DONE;") + +(define_insn "*one_cmpldi2_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] + "TARGET_64BIT && ix86_unary_operator_ok (NOT, DImode, operands)" + "not{q}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "DI")]) + +(define_insn "*one_cmpldi2_2_rex64" + [(set (reg 17) + (compare (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (not:DI (match_dup 1)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, DImode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "DI")]) -(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_split + [(set (reg 17) + (compare (not:DI (match_operand:DI 1 "nonimmediate_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "") + (not:DI (match_dup 1)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (xor:DI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (xor:DI (match_dup 1) (const_int -1)))])] + "") -(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_expand "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "")))] + "" + "ix86_expand_unary_operator (NOT, SImode, operands); DONE;") -(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 "*one_cmplsi2_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] + "ix86_unary_operator_ok (NOT, SImode, operands)" + "not{l}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +;; ??? Currently never generated - xor is used instead. +(define_insn "*one_cmplsi2_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (not:SI (match_operand:SI 1 "register_operand" "0"))))] + "TARGET_64BIT && ix86_unary_operator_ok (NOT, SImode, operands)" + "not{l}\t%k0" + [(set_attr "type" "negnot") + (set_attr "mode" "SI")]) + +(define_insn "*one_cmplsi2_2" + [(set (reg 17) + (compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (not:SI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, SImode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "SI")]) -(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_split + [(set (reg 17) + (compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "") + (not:SI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (xor:SI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (xor:SI (match_dup 1) (const_int -1)))])] + "") -(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 +;; ??? Currently never generated - xor is used instead. +(define_insn "*one_cmplsi2_2_zext" + [(set (reg 17) + (compare (not:SI (match_operand:SI 1 "register_operand" "0")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (not:SI (match_dup 1))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, SImode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "SI")]) -(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. */ +(define_split + [(set (reg 17) + (compare (not:SI (match_operand:SI 1 "register_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (not:SI (match_dup 1))))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (xor:SI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (zero_extend:DI (xor:SI (match_dup 1) (const_int -1))))])] + "") - 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_expand "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (not:HI (match_operand:HI 1 "nonimmediate_operand" "")))] + "TARGET_HIMODE_MATH" + "ix86_expand_unary_operator (NOT, HImode, operands); DONE;") -(define_insn "one_cmplhi2" +(define_insn "*one_cmplhi2_1" [(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); - } -}") + "ix86_unary_operator_ok (NOT, HImode, operands)" + "not{w}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "HI")]) + +(define_insn "*one_cmplhi2_2" + [(set (reg 17) + (compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (not:HI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NEG, HImode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "HI")]) -(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. */ +(define_split + [(set (reg 17) + (compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "") + (not:HI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (xor:HI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (xor:HI (match_dup 1) (const_int -1)))])] + "") - 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); -}") +;; %%% Potential partial reg stall on alternative 1. What to do? +(define_expand "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "")))] + "TARGET_QIMODE_MATH" + "ix86_expand_unary_operator (NOT, QImode, operands); DONE;") + +(define_insn "*one_cmplqi2_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] + "ix86_unary_operator_ok (NOT, QImode, operands)" + "@ + not{b}\t%0 + not{l}\t%k0" + [(set_attr "type" "negnot") + (set_attr "mode" "QI,SI")]) + +(define_insn "*one_cmplqi2_2" + [(set (reg 17) + (compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (not:QI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, QImode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +(define_split + [(set (reg 17) + (compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "") + (not:QI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (xor:QI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (xor:QI (match_dup 1) (const_int -1)))])] + "") -;;- arithmetic shift instructions +;; 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" "")))] + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (ashift:DI (match_operand:DI 1 "shiftdi_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))])] "" - " { - if (GET_CODE (operands[2]) != CONST_INT - || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) { - operands[2] = copy_to_mode_reg (QImode, operands[2]); - emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1], - operands[2])); + emit_insn (gen_ashldi3_1 (operands[0], operands[1], operands[2])); + DONE; } - else - emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2])); - + ix86_expand_binary_operator (ASHIFT, DImode, operands); 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')" - "* +}) + +(define_insn "*ashldi3_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0,r") + (match_operand:QI 2 "nonmemory_operand" "cJ,M"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, DImode, operands)" { - 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) + switch (get_attr_type (insn)) { - output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ - output_asm_insn (AS2 (xor%L2,%2,%2), xops); + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + if (!rtx_equal_p (operands[0], operands[1])) + abort (); + return "add{q}\t{%0, %0|%0, %0}"; - if (INTVAL (xops[0]) > 32) - { - xops[0] = GEN_INT (INTVAL (xops[0]) - 32); - output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */ - } + case TYPE_LEA: + if (GET_CODE (operands[2]) != CONST_INT + || (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 3) + abort (); + operands[1] = gen_rtx_MULT (DImode, operands[1], + GEN_INT (1 << INTVAL (operands[2]))); + return "lea{q}\t{%a1, %0|%0, %a1}"; + + default: + if (REG_P (operands[2])) + return "sal{q}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{q}\t%0"; + else + return "sal{q}\t{%2, %0|%0, %2}"; } - else +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "DI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "immediate_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (mult:DI (match_dup 1) + (match_dup 2)))] + "operands[2] = GEN_INT (trunc_int_for_mode (1 << INTVAL (operands[2]), + DImode));") + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashldi3_cmp_rex64" + [(set (reg 17) + (compare + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "e")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashift:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFT, DImode, operands)" +{ + switch (get_attr_type (insn)) { - output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - } - RET; -}") + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{q}\t{%0, %0|%0, %0}"; -(define_insn "ashldi3_non_const_int" - [(set (match_operand:DI 0 "register_operand" "=&r") + default: + if (REG_P (operands[2])) + return "sal{q}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{q}\t%0"; + else + return "sal{q}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "DI")]) + +(define_insn "ashldi3_1" + [(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; + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) - 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 (); +(define_insn "*ashldi3_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "#" + [(set_attr "type" "multi")]) - 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_split + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" + [(const_int 0)] + "ix86_split_ashldi (operands, operands[3]); DONE;") -(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_split + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(const_int 0)] + "ix86_split_ashldi (operands, NULL_RTX); DONE;") + +(define_insn "x86_shld_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m") + (ior:SI (ashift:SI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "I,c")) + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC 17))] "" + "@ + shld{l}\t{%2, %1, %0|%0, %1, %2} + shld{l}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "mode" "SI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + +(define_expand "x86_shift_adj_1" + [(set (reg:CCZ 17) + (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") + (const_int 32)) + (const_int 0))) + (set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (ne (reg:CCZ 17) (const_int 0)) + (match_operand:SI 1 "register_operand" "") + (match_dup 0))) + (set (match_dup 1) + (if_then_else:SI (ne (reg:CCZ 17) (const_int 0)) + (match_operand:SI 3 "register_operand" "r") + (match_dup 1)))] + "TARGET_CMOVE" "") -(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 "x86_shift_adj_2" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:SI 1 "register_operand" "")) + (use (match_operand:QI 2 "register_operand" ""))] "" - "") +{ + rtx label = gen_label_rtx (); + rtx tmp; -(define_expand "ashlqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "") + emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32))); -;; 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. + tmp = gen_rtx_REG (CCZmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + JUMP_LABEL (tmp) = label; -(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);") + emit_move_insn (operands[0], operands[1]); + emit_move_insn (operands[1], const0_rtx); -;; 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);") + emit_label (label); + LABEL_NUSES (label) = 1; -(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);") + DONE; +}) -(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")))] +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] "" - "* return output_ashl (insn, operands);") + "ix86_expand_binary_operator (ASHIFT, SImode, operands); DONE;") -(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);") +(define_insn "*ashlsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r") + (match_operand:QI 2 "nonmemory_operand" "cI,M"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFT, SImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + if (!rtx_equal_p (operands[0], operands[1])) + abort (); + return "add{l}\t{%0, %0|%0, %0}"; -;; 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);") + case TYPE_LEA: + return "#"; -;; See comment above `ashldi3' about how this works. + default: + if (REG_P (operands[2])) + return "sal{l}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{l}\t%0"; + else + return "sal{l}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "SI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand 0 "register_operand" "") + (ashift (match_operand 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = GEN_INT (trunc_int_for_mode (1 << INTVAL (operands[2]), + Pmode)); + pat = gen_rtx_MULT (Pmode, operands[1], operands[2]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +}) + +(define_insn "*ashlsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (ashift:SI (match_operand:SI 1 "register_operand" "0,r") + (match_operand:QI 2 "nonmemory_operand" "cI,M")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, SImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{l}\t{%k0, %k0|%k0, %k0}"; -(define_expand "ashrdi3" + case TYPE_LEA: + return "#"; + + default: + if (REG_P (operands[2])) + return "sal{l}\t{%b2, %k0|%k0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{l}\t%k0"; + else + return "sal{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "SI")]) + +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split [(set (match_operand:DI 0 "register_operand" "") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - " + (zero_extend:DI (ashift (match_operand 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))) + (clobber (reg:CC 17))] + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) (zero_extend:DI (subreg:SI (mult:SI (match_dup 1) (match_dup 2)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = GEN_INT (trunc_int_for_mode (1 << INTVAL (operands[2]), + Pmode)); +}) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashlsi3_cmp" + [(set (reg 17) + (compare + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashift:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { - if (GET_CODE (operands[2]) != CONST_INT - || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + switch (get_attr_type (insn)) { - 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; -}") + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{l}\t{%0, %0|%0, %0}"; -(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)))] - "" - "* + default: + if (REG_P (operands[2])) + return "sal{l}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{l}\t%0"; + else + return "sal{l}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "SI")]) + +(define_insn "*ashlsi3_cmp_zext" + [(set (reg 17) + (compare + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { - rtx low[2], high[2], xops[4]; + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{l}\t{%k0, %k0|%k0, %k0}"; - 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); + default: + if (REG_P (operands[2])) + return "sal{l}\t{%b2, %k0|%k0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{l}\t%k0"; + else + return "sal{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (cond [(and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "SI")]) - 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); +(define_expand "ashlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (ASHIFT, HImode, operands); DONE;") - RET; -}") +(define_insn "*ashlhi3_1_lea" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r") + (match_operand:QI 2 "nonmemory_operand" "cI,M"))) + (clobber (reg:CC 17))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_LEA: + return "#"; + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{w}\t{%0, %0|%0, %0}"; -(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')" - "* + default: + if (REG_P (operands[2])) + return "sal{w}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{w}\t%0"; + else + return "sal{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "HI,SI")]) + +(define_insn "*ashlhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI"))) + (clobber (reg:CC 17))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" { - rtx xops[4], low[1], high[1]; + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{w}\t{%0, %0|%0, %0}"; - CC_STATUS_INIT; + default: + if (REG_P (operands[2])) + return "sal{w}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{w}\t%0"; + else + return "sal{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "HI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashlhi3_cmp" + [(set (reg 17) + (compare + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{w}\t{%0, %0|%0, %0}"; - split_di (operands, 1, low, high); - xops[0] = operands[2]; - xops[1] = const1_rtx; - xops[2] = low[0]; - xops[3] = high[0]; + default: + if (REG_P (operands[2])) + return "sal{w}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{w}\t%0"; + else + return "sal{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "HI")]) - if (INTVAL (xops[0]) > 31) +(define_expand "ashlqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (ASHIFT, QImode, operands); DONE;") + +;; %%% Potential partial reg stall on alternative 2. What to do? + +(define_insn "*ashlqi3_1_lea" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,r") + (match_operand:QI 2 "nonmemory_operand" "cI,cI,M"))) + (clobber (reg:CC 17))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" +{ + switch (get_attr_type (insn)) { - 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 */ + case TYPE_LEA: + return "#"; + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) + return "add{l}\t{%k0, %k0|%k0, %k0}"; + else + return "add{b}\t{%0, %0|%0, %0}"; - if (INTVAL (xops[0]) > 32) - { - xops[0] = GEN_INT (INTVAL (xops[0]) - 32); - output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */ + default: + if (REG_P (operands[2])) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%b2, %k0|%k0, %b2}"; + else + return "sal{b}\t{%b2, %0|%0, %b2}"; + } + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t%0"; + else + return "sal{b}\t%0"; + } + else + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%2, %k0|%k0, %2}"; + else + return "sal{b}\t{%2, %0|%0, %2}"; } } - else +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "QI,SI,SI")]) + +(define_insn "*ashlqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "cI,cI"))) + (clobber (reg:CC 17))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" +{ + switch (get_attr_type (insn)) { - output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) + return "add{l}\t{%k0, %k0|%k0, %k0}"; + else + return "add{b}\t{%0, %0|%0, %0}"; + + default: + if (REG_P (operands[2])) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%b2, %k0|%k0, %b2}"; + else + return "sal{b}\t{%b2, %0|%0, %b2}"; + } + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t%0"; + else + return "sal{b}\t%0"; + } + else + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%2, %k0|%k0, %2}"; + else + return "sal{b}\t{%2, %0|%0, %2}"; + } } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "QI,SI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashlqi3_cmp" + [(set (reg 17) + (compare + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (ashift:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + if (operands[2] != const1_rtx) + abort (); + return "add{b}\t{%0, %0|%0, %0}"; - RET; -}") + default: + if (REG_P (operands[2])) + return "sal{b}\t{%b2, %0|%0, %b2}"; + else if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)) + return "sal{b}\t%0"; + else + return "sal{b}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set_attr "mode" "QI")]) + +;; See comment above `ashldi3' about how this works. + +(define_expand "ashrdi3" + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (ashiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))])] + "" +{ + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) + { + emit_insn (gen_ashrdi3_1 (operands[0], operands[1], operands[2])); + DONE; + } + ix86_expand_binary_operator (ASHIFTRT, DImode, operands); + DONE; +}) + +(define_insn "ashrdi3_63_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=*d,rm") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "*a,0") + (match_operand:DI 2 "const_int_operand" "i,i"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && INTVAL (operands[2]) == 63 && (TARGET_USE_CLTD || optimize_size) + && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" + "@ + {cqto|cqo} + sar{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") + (set_attr "mode" "DI")]) + +(define_insn "*ashrdi3_1_one_bit_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, DImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "sar{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*ashrdi3_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "J,c"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" + "@ + sar{q}\t{%2, %0|%0, %2} + sar{q}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrdi3_one_bit_cmp_rex64" + [(set (reg 17) + (compare + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" + "sar{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrdi3_cmp_rex64" + [(set (reg 17) + (compare + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "n")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" + "sar{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + + +(define_insn "ashrdi3_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) -(define_insn "ashrdi3_non_const_int" - [(set (match_operand:DI 0 "register_operand" "=&r") +(define_insn "*ashrdi3_2" + [(set (match_operand:DI 0 "register_operand" "=r") (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c")))] + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "#" + [(set_attr "type" "multi")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" + [(const_int 0)] + "ix86_split_ashrdi (operands, operands[3]); DONE;") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(const_int 0)] + "ix86_split_ashrdi (operands, NULL_RTX); DONE;") + +(define_insn "x86_shrd_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m") + (ior:SI (ashiftrt:SI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "I,c")) + (ashift:SI (match_operand:SI 1 "register_operand" "r,r") + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC 17))] + "" + "@ + shrd{l}\t{%2, %1, %0|%0, %1, %2} + shrd{l}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "pent_pair" "np") + (set_attr "ppro_uops" "few") + (set_attr "mode" "SI")]) + +(define_expand "x86_shift_adj_3" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:SI 1 "register_operand" "")) + (use (match_operand:QI 2 "register_operand" ""))] "" - "* { - rtx xops[5], low[1], high[1]; + rtx label = gen_label_rtx (); + rtx tmp; - CC_STATUS_INIT; + emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32))); - 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 (); + tmp = gen_rtx_REG (CCZmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + JUMP_LABEL (tmp) = label; - 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; -}") + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_ashrsi3_31 (operands[1], operands[1], GEN_INT (31))); + + emit_label (label); + LABEL_NUSES (label) = 1; + + DONE; +}) (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" + [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0") + (match_operand:SI 2 "const_int_operand" "i,i"))) + (clobber (reg:CC 17))] + "INTVAL (operands[2]) == 31 && (TARGET_USE_CLTD || optimize_size) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "@ - sar%L0 $31,%0 - cltd") + {cltd|cdq} + sar{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_31_zext" + [(set (match_operand:DI 0 "register_operand" "=*d,r") + (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "*a,0") + (match_operand:SI 2 "const_int_operand" "i,i")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && (TARGET_USE_CLTD || optimize_size) + && INTVAL (operands[2]) == 31 + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "@ + {cltd|cdq} + sar{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") + (set_attr "mode" "SI")]) + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (ASHIFTRT, SImode, operands); DONE;") -(define_insn "ashrsi3" +(define_insn "*ashrsi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "sar{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*ashrsi3_1_one_bit_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "sar{l}\t%k0" + [(set_attr "type" "ishift") + (set_attr "length" "2")]) + +(define_insn "*ashrsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "@ + sar{l}\t{%2, %0|%0, %2} + sar{l}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "@ + sar{l}\t{%2, %k0|%k0, %2} + sar{l}\t{%b2, %k0|%k0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrsi3_one_bit_cmp" + [(set (reg 17) + (compare + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "sar{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*ashrsi3_one_bit_cmp_zext" + [(set (reg 17) + (compare + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "sar{l}\t%k0" + [(set_attr "type" "ishift") + (set_attr "length" "2")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrsi3_cmp" + [(set (reg 17) + (compare + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "sar{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*ashrsi3_cmp_zext" + [(set (reg 17) + (compare + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "sar{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (ASHIFTRT, HImode, operands); DONE;") -(define_insn "ashrhi3" +(define_insn "*ashrhi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "sar{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*ashrhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" + "@ + sar{w}\t{%2, %0|%0, %2} + sar{w}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrhi3_one_bit_cmp" + [(set (reg 17) + (compare + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashiftrt:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" + "sar{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrhi3_cmp" + [(set (reg 17) + (compare + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashiftrt:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" + "sar{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (ASHIFTRT, QImode, operands); DONE;") -(define_insn "ashrqi3" +(define_insn "*ashrqi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, QImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "sar{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*ashrqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" + "@ + sar{b}\t{%2, %0|%0, %2} + sar{b}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrqi3_one_bit_cmp" + [(set (reg 17) + (compare + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "I")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=rm") + (ashiftrt:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" + "sar{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*ashrqi3_cmp" + [(set (reg 17) + (compare + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=rm") + (ashiftrt:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" + "sar{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) -;;- logical shift instructions +;; 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" "")))] + [(parallel [(set (match_operand:DI 0 "shiftdi_operand" "") + (lshiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))])] "" - " { - if (GET_CODE (operands[2]) != CONST_INT - || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + if (!TARGET_64BIT && TARGET_CMOVE && ! immediate_operand (operands[2], QImode)) { - operands[2] = copy_to_mode_reg (QImode, operands[2]); - emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1], - operands[2])); + emit_insn (gen_lshrdi3_1 (operands[0], operands[1], operands[2])); + DONE; } - else - emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2])); - + ix86_expand_binary_operator (LSHIFTRT, DImode, operands); 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") +}) + +(define_insn "*lshrdi3_1_one_bit_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "shr{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*lshrdi3_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "J,c"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "@ + shr{q}\t{%2, %0|%0, %2} + shr{q}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrdi3_cmp_one_bit_rex64" + [(set (reg 17) + (compare + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (lshiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrdi3_cmp_rex64" + [(set (reg 17) + (compare + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "e")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (lshiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + +(define_insn "lshrdi3_1" + [(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; -}") + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (match_scratch:SI 3 "=&r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE" + "#" + [(set_attr "type" "multi")]) -(define_insn "lshrdi3_non_const_int" - [(set (match_operand:DI 0 "register_operand" "=&r") +(define_insn "*lshrdi3_2" + [(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]; + (match_operand:QI 2 "nonmemory_operand" "Jc"))) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "#" + [(set_attr "type" "multi")]) - CC_STATUS_INIT; +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_CMOVE && reload_completed" + [(const_int 0)] + "ix86_split_lshrdi (operands, operands[3]); DONE;") - 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 (); +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "!TARGET_64BIT && reload_completed" + [(const_int 0)] + "ix86_split_lshrdi (operands, NULL_RTX); DONE;") - 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_expand "lshrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (LSHIFTRT, SImode, operands); DONE;") -(define_insn "lshrsi3" +(define_insn "*lshrsi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "shr{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*lshrsi3_1_one_bit_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "0")) + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "shr{l}\t%k0" + [(set_attr "type" "ishift") + (set_attr "length" "2")]) + +(define_insn "*lshrsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "@ + shr{l}\t{%2, %0|%0, %2} + shr{l}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "@ + shr{l}\t{%2, %k0|%k0, %2} + shr{l}\t{%b2, %k0|%k0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrsi3_one_bit_cmp" + [(set (reg 17) + (compare + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*lshrsi3_cmp_one_bit_zext" + [(set (reg 17) + (compare + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{l}\t%k0" + [(set_attr "type" "ishift") + (set_attr "length" "2")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrsi3_cmp" + [(set (reg 17) + (compare + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*lshrsi3_cmp_zext" + [(set (reg 17) + (compare + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (LSHIFTRT, HImode, operands); DONE;") -(define_insn "lshrhi3" +(define_insn "*lshrhi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "shr{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*lshrhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "@ + shr{w}\t{%2, %0|%0, %2} + shr{w}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrhi3_one_bit_cmp" + [(set (reg 17) + (compare + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (lshiftrt:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrhi3_cmp" + [(set (reg 17) + (compare + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (lshiftrt:HI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" + "shr{w}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (LSHIFTRT, QImode, operands); DONE;") -(define_insn "lshrqi3" +(define_insn "*lshrqi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, QImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "shr{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*lshrqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" + "@ + shr{b}\t{%2, %0|%0, %2} + shr{b}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrqi2_one_bit_cmp" + [(set (reg 17) + (compare + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (lshiftrt:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO) + && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" + "shr{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*lshrqi2_cmp" + [(set (reg 17) + (compare + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "immediate_operand" "I")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (lshiftrt:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" + "shr{b}\t{%2, %0|%0, %2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) -;;- rotate instructions +;; Rotate instructions -(define_insn "rotlsi3" +(define_expand "rotldi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (ROTATE, DImode, operands); DONE;") + +(define_insn "*rotlsi3_1_one_bit_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, DImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "rol{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotldi3_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "e,c"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, DImode, operands)" + "@ + rol{q}\t{%2, %0|%0, %2} + rol{q}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + +(define_expand "rotlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "" + "ix86_expand_binary_operator (ROTATE, SImode, operands); DONE;") + +(define_insn "*rotlsi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "rol{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotlsi3_1_one_bit_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "rol{l}\t%k0" + [(set_attr "type" "ishift") + (set_attr "length" "2")]) + +(define_insn "*rotlsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, SImode, operands)" + "@ + rol{l}\t{%2, %0|%0, %2} + rol{l}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*rotlsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI + (rotate:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, SImode, operands)" + "@ + rol{l}\t{%2, %k0|%k0, %2} + rol{l}\t{%b2, %k0|%k0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_expand "rotlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (ROTATE, HImode, operands); DONE;") -(define_insn "rotlhi3" +(define_insn "*rotlhi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "rol{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotlhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, HImode, operands)" + "@ + rol{w}\t{%2, %0|%0, %2} + rol{w}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) -(define_insn "rotlqi3" +(define_expand "rotlqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (ROTATE, QImode, operands); DONE;") + +(define_insn "*rotlqi3_1_one_bit" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "cI")))] + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, QImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "rol{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotlqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") + (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATE, QImode, operands)" + "@ + rol{b}\t{%2, %0|%0, %2} + rol{b}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) + +(define_expand "rotrdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "ix86_expand_binary_operator (ROTATERT, DImode, operands); DONE;") + +(define_insn "*rotrdi3_1_one_bit_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, DImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "ror{q}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:DI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotrdi3_1_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "J,c"))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, DImode, operands)" + "@ + ror{q}\t{%2, %0|%0, %2} + ror{q}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "DI")]) + +(define_expand "rotrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] "" - "* -{ - if (REG_P (operands[2])) - return AS2 (rol%B0,%b2,%0); - else - return AS2 (rol%B0,%2,%0); -}") + "ix86_expand_binary_operator (ROTATERT, SImode, operands); DONE;") -(define_insn "rotrsi3" +(define_insn "*rotrsi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "ror{l}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotrsi3_1_one_bit_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_1_operand" "")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, SImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "ror{l}\t%k0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand:SI 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotrsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, SImode, operands)" + "@ + ror{l}\t{%2, %0|%0, %2} + ror{l}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_insn "*rotrsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI + (rotatert:SI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c")))) + (clobber (reg:CC 17))] + "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, SImode, operands)" + "@ + ror{l}\t{%2, %k0|%k0, %2} + ror{l}\t{%b2, %k0|%k0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "SI")]) + +(define_expand "rotrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_HIMODE_MATH" + "ix86_expand_binary_operator (ROTATERT, HImode, operands); DONE;") -(define_insn "rotrhi3" +(define_insn "*rotrhi3_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, HImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "ror{w}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, HImode, operands)" + "@ + ror{w}\t{%2, %0|%0, %2} + ror{w}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "HI")]) + +(define_expand "rotrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC 17))] + "TARGET_QIMODE_MATH" + "ix86_expand_binary_operator (ROTATERT, QImode, operands); DONE;") -(define_insn "rotrqi3" +(define_insn "*rotrqi3_1_one_bit" [(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); -}") + (match_operand:QI 2 "const_int_1_operand" ""))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, QImode, operands) + && (TARGET_PENTIUM || TARGET_PENTIUMPRO)" + "ror{b}\t%0" + [(set_attr "type" "ishift") + (set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_string "2") + (const_string "*")))]) + +(define_insn "*rotrqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") + (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "I,c"))) + (clobber (reg:CC 17))] + "ix86_binary_operator_ok (ROTATERT, QImode, operands)" + "@ + ror{b}\t{%2, %0|%0, %2} + ror{b}\t{%b2, %0|%0, %b2}" + [(set_attr "type" "ishift") + (set_attr "mode" "QI")]) -/* -;; 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. +;; Bit set / bit test instructions -(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"))] +(define_expand "extv" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extract:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] "" - " { - if (GET_CODE (operands[1]) != CONST_INT - || GET_CODE (operands[2]) != CONST_INT) + /* Handle extractions from %ah et al. */ + if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8) FAIL; - if (! (INTVAL (operands[1]) == 8 - && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0)) - && ! INTVAL (operands[1]) == 1) + /* From mips.md: extract_bit_field doesn't verify that our source + matches the predicate, so check it again here. */ + if (! register_operand (operands[1], VOIDmode)) 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")))] +(define_expand "extzv" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extract:SI (match_operand 1 "ext_register_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand:SI 3 "immediate_operand" "")))] "" - "* { - 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); -}") + /* Handle extractions from %ah et al. */ + if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8) + FAIL; -;; ??? All bets are off if operand 0 is a volatile MEM reference. -;; The CPU may access unspecified bytes around the actual target byte. + /* From mips.md: extract_bit_field doesn't verify that our source + matches the predicate, so check it again here. */ + if (! register_operand (operands[1], VOIDmode)) + FAIL; +}) -(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])" - "* +(define_expand "insv" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "")) + (match_operand:SI 3 "register_operand" ""))] + "" { - 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); - } - } + /* Handle extractions from %ah et al. */ + if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8) + FAIL; - if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) - return AS2 (test%L0,%1,%0); + /* From mips.md: insert_bit_field doesn't verify that our source + matches the predicate, so check it again here. */ + if (! register_operand (operands[0], VOIDmode)) + FAIL; +}) - return AS2 (test%L1,%0,%1); -}") +;; %%% bts, btr, btc, bt. ;; 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'. +;; %%% Do the expansion to SImode. If PII, do things the xor+setcc way +;; to avoid partial register stalls. Otherwise do things the setcc+movzx +;; way, which can later delete the movzx if only QImode is needed. + (define_expand "seq" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (eq:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (eq:QI (reg:CC 17) (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); -}") + "if (ix86_expand_setcc (EQ, operands[0])) DONE; else FAIL;") (define_expand "sne" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (ne:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ne:QI (reg:CC 17) (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); -}") + "if (ix86_expand_setcc (NE, operands[0])) DONE; else FAIL;") (define_expand "sgt" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (gt:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (gt:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (GT, operands[0])) DONE; else FAIL;") (define_expand "sgtu" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (gtu:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (gtu:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (GTU, operands[0])) DONE; else FAIL;") (define_expand "slt" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (lt:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (lt:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (LT, operands[0])) DONE; else FAIL;") (define_expand "sltu" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (ltu:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ltu:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (LTU, operands[0])) DONE; else FAIL;") (define_expand "sge" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (ge:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (ge:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (GE, operands[0])) DONE; else FAIL;") (define_expand "sgeu" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (geu:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (geu:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (GEU, operands[0])) DONE; else FAIL;") (define_expand "sle" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (le:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (le:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (LE, operands[0])) DONE; else FAIL;") (define_expand "sleu" - [(match_dup 1) - (set (match_operand:QI 0 "register_operand" "") - (leu:QI (cc0) (const_int 0)))] + [(set (match_operand:QI 0 "register_operand" "") + (leu:QI (reg:CC 17) (const_int 0)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "if (ix86_expand_setcc (LEU, operands[0])) DONE; else FAIL;") -;; 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_expand "sunordered" + [(set (match_operand:QI 0 "register_operand" "") + (unordered:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNORDERED, operands[0])) DONE; else FAIL;") -(define_insn "*setcc" +(define_expand "sordered" + [(set (match_operand:QI 0 "register_operand" "") + (ordered:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387" + "if (ix86_expand_setcc (ORDERED, operands[0])) DONE; else FAIL;") + +(define_expand "suneq" + [(set (match_operand:QI 0 "register_operand" "") + (uneq:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNEQ, operands[0])) DONE; else FAIL;") + +(define_expand "sunge" + [(set (match_operand:QI 0 "register_operand" "") + (unge:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNGE, operands[0])) DONE; else FAIL;") + +(define_expand "sungt" + [(set (match_operand:QI 0 "register_operand" "") + (ungt:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNGT, operands[0])) DONE; else FAIL;") + +(define_expand "sunle" + [(set (match_operand:QI 0 "register_operand" "") + (unle:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNLE, operands[0])) DONE; else FAIL;") + +(define_expand "sunlt" + [(set (match_operand:QI 0 "register_operand" "") + (unlt:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (UNLT, operands[0])) DONE; else FAIL;") + +(define_expand "sltgt" + [(set (match_operand:QI 0 "register_operand" "") + (ltgt:QI (reg:CC 17) (const_int 0)))] + "TARGET_80387 || TARGET_SSE" + "if (ix86_expand_setcc (LTGT, operands[0])) DONE; else FAIL;") + +(define_insn "*setcc_1" [(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)" - "* + (match_operator:QI 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]))] + "" + "set%C1\t%0" + [(set_attr "type" "setcc") + (set_attr "mode" "QI")]) + +(define_insn "setcc_2" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) + (match_operator:QI 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]))] + "" + "set%C1\t%0" + [(set_attr "type" "setcc") + (set_attr "mode" "QI")]) + +;; In general it is not safe to assume too much about CCmode registers, +;; so simplify-rtx stops when it sees a second one. Under certain +;; conditions this is safe on x86, so help combine not create +;; +;; seta %al +;; testb %al, %al +;; sete %al + +(define_split + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ne:QI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)))] + "" + [(set (match_dup 0) (match_dup 1))] { - 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); - } + PUT_MODE (operands[1], QImode); +}) - if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT)) - return (char *)0; - return AS1(set%D1,%0); -}") +(define_split + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) + (ne:QI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)))] + "" + [(set (match_dup 0) (match_dup 1))] +{ + PUT_MODE (operands[1], QImode); +}) +(define_split + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (eq:QI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)))] + "" + [(set (match_dup 0) (match_dup 1))] +{ + rtx new_op1 = copy_rtx (operands[1]); + operands[1] = new_op1; + PUT_MODE (new_op1, QImode); + PUT_CODE (new_op1, REVERSE_CONDITION (GET_CODE (new_op1), + GET_MODE (XEXP (new_op1, 0)))); + + /* Make sure that (a) the CCmode we have for the flags is strong + enough for the reversed compare or (b) we have a valid FP compare. */ + if (! ix86_comparison_operator (new_op1, VOIDmode)) + FAIL; +}) + +(define_split + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) + (eq:QI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)))] + "" + [(set (match_dup 0) (match_dup 1))] +{ + rtx new_op1 = copy_rtx (operands[1]); + operands[1] = new_op1; + PUT_MODE (new_op1, QImode); + PUT_CODE (new_op1, REVERSE_CONDITION (GET_CODE (new_op1), + GET_MODE (XEXP (new_op1, 0)))); + + /* Make sure that (a) the CCmode we have for the flags is strong + enough for the reversed compare or (b) we have a valid FP compare. */ + if (! ix86_comparison_operator (new_op1, VOIDmode)) + FAIL; +}) + +;; The SSE store flag instructions saves 0 or 0xffffffff to the result. +;; subsequent logical operations are used to imitate conditional moves. +;; 0xffffffff is NaN, but not in normalized form, so we can't represent +;; it directly. Futher holding this value in pseudo register might bring +;; problem in implicit normalization in spill code. +;; So we don't define FLOAT_STORE_FLAG_VALUE and create these +;; instructions after reload by splitting the conditional move patterns. + +(define_insn "*sse_setccsf" + [(set (match_operand:SF 0 "register_operand" "=x") + (match_operator:SF 1 "sse_comparison_operator" + [(match_operand:SF 2 "register_operand" "0") + (match_operand:SF 3 "nonimmediate_operand" "xm")]))] + "TARGET_SSE && reload_completed" + "cmp%D1ss\t{%3, %0|%0, %3}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_insn "*sse_setccdf" + [(set (match_operand:DF 0 "register_operand" "=Y") + (match_operator:DF 1 "sse_comparison_operator" + [(match_operand:DF 2 "register_operand" "0") + (match_operand:DF 3 "nonimmediate_operand" "Ym")]))] + "TARGET_SSE2 && reload_completed" + "cmp%D1sd\t{%3, %0|%0, %3}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) ;; 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'. +;; generates reg 17. Generate an equality comparison if `beq' or `bne'. (define_expand "beq" - [(match_dup 1) - (set (pc) - (if_then_else (eq (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (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); -}") + "ix86_expand_branch (EQ, operands[0]); DONE;") (define_expand "bne" - [(match_dup 1) - (set (pc) - (if_then_else (ne (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (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); -}") - + "ix86_expand_branch (NE, operands[0]); DONE;") (define_expand "bgt" - [(match_dup 1) - (set (pc) - (if_then_else (gt (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (GT, operands[0]); DONE;") (define_expand "bgtu" - [(match_dup 1) - (set (pc) - (if_then_else (gtu (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (GTU, operands[0]); DONE;") (define_expand "blt" - [(match_dup 1) - (set (pc) - (if_then_else (lt (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") - + "ix86_expand_branch (LT, operands[0]); DONE;") (define_expand "bltu" - [(match_dup 1) - (set (pc) - (if_then_else (ltu (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (LTU, operands[0]); DONE;") (define_expand "bge" - [(match_dup 1) - (set (pc) - (if_then_else (ge (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (GE, operands[0]); DONE;") (define_expand "bgeu" - [(match_dup 1) - (set (pc) - (if_then_else (geu (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (GEU, operands[0]); DONE;") (define_expand "ble" - [(match_dup 1) - (set (pc) - (if_then_else (le (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (LE, operands[0]); DONE;") (define_expand "bleu" - [(match_dup 1) - (set (pc) - (if_then_else (leu (cc0) - (const_int 0)) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + "ix86_expand_branch (LEU, operands[0]); DONE;") -(define_insn "" +(define_expand "bunordered" [(set (pc) - (if_then_else (match_operator 0 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 1 "" "")) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) (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; + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNORDERED, operands[0]); DONE;") - return AS1(j%D0,%l1); -}") +(define_expand "bordered" + [(set (pc) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (ORDERED, operands[0]); DONE;") -(define_insn "" +(define_expand "buneq" [(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; + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNEQ, operands[0]); DONE;") - return AS1(j%d0,%l1); -}") - -;; Unconditional and other jump instructions +(define_expand "bunge" + [(set (pc) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNGE, operands[0]); DONE;") -(define_insn "jump" +(define_expand "bungt" [(set (pc) - (label_ref (match_operand 0 "" "")))] - "" - "jmp %l0" - [(set_attr "memory" "none")]) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNGT, operands[0]); DONE;") -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))] - "" - "* -{ - CC_STATUS_INIT; +(define_expand "bunle" + [(set (pc) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNLE, operands[0]); DONE;") - return AS1 (jmp,%*%0); -}" - [(set_attr "memory" "none")]) +(define_expand "bunlt" + [(set (pc) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (UNLT, operands[0]); DONE;") -;; ??? could transform while(--i > 0) S; to if (--i > 0) do S; while(--i); -;; if S does not change i +(define_expand "bltgt" + [(set (pc) + (if_then_else (match_dup 1) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_80387 || TARGET_SSE" + "ix86_expand_branch (LTGT, operands[0]); DONE;") -(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 "*jcc_1" + [(set (pc) + (if_then_else (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] "" - "") + "%+j%C1\t%l0" + [(set_attr "type" "ibr") + (set (attr "prefix_0f") + (if_then_else (and (ge (minus (match_dup 0) (pc)) + (const_int -128)) + (lt (minus (match_dup 0) (pc)) + (const_int 124))) + (const_int 0) + (const_int 1)))]) + +(define_insn "*jcc_2" + [(set (pc) + (if_then_else (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "%+j%c1\t%l0" + [(set_attr "type" "ibr") + (set (attr "prefix_0f") + (if_then_else (and (ge (minus (match_dup 0) (pc)) + (const_int -128)) + (lt (minus (match_dup 0) (pc)) + (const_int 124))) + (const_int 0) + (const_int 1)))]) + +;; In general it is not safe to assume too much about CCmode registers, +;; so simplify-rtx stops when it sees a second one. Under certain +;; conditions this is safe on x86, so help combine not create +;; +;; seta %al +;; testb %al, %al +;; je Lfoo -(define_insn "" +(define_split [(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)))] + (if_then_else (ne (match_operator 0 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] "" - "* + [(set (pc) + (if_then_else (match_dup 0) + (label_ref (match_dup 1)) + (pc)))] { - CC_STATUS_INIT; - - if (GET_CODE (operands[1]) == REG && REGNO (operands[2]) == 2 && - operands[2] == constm1_rtx && ix86_cpu == PROCESSOR_K6) - return \"loop %l3\"; + PUT_MODE (operands[0], VOIDmode); +}) + +(define_split + [(set (pc) + (if_then_else (eq (match_operator 0 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + [(set (pc) + (if_then_else (match_dup 0) + (label_ref (match_dup 1)) + (pc)))] +{ + rtx new_op0 = copy_rtx (operands[0]); + operands[0] = new_op0; + PUT_MODE (new_op0, VOIDmode); + PUT_CODE (new_op0, REVERSE_CONDITION (GET_CODE (new_op0), + GET_MODE (XEXP (new_op0, 0)))); + + /* Make sure that (a) the CCmode we have for the flags is strong + enough for the reversed compare or (b) we have a valid FP compare. */ + if (! ix86_comparison_operator (new_op0, VOIDmode)) + FAIL; +}) - if (operands[2] == constm1_rtx) - output_asm_insn (AS1 (dec%L1,%1), operands); +;; Define combination compare-and-branch fp compare instructions to use +;; during early optimization. Splitting the operation apart early makes +;; for bad code when we want to reverse the operation. - else if (operands[2] == const1_rtx) - output_asm_insn (AS1 (inc%L1,%1), operands); +(define_insn "*fp_jcc_1" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_CMOVE && TARGET_80387 + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") - else - output_asm_insn (AS2 (add%L1,%2,%1), operands); +(define_insn "*fp_jcc_1_sse" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f#x,x#f") + (match_operand 2 "nonimmediate_operand" "f#x,xm#f")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_80387 + && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") - return AS1 (%J0,%l3); -}") +(define_insn "*fp_jcc_1_sse_only" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "x") + (match_operand 2 "nonimmediate_operand" "xm")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") -(define_insn "" +(define_insn "*fp_jcc_2" [(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); + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) + (pc) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_CMOVE && TARGET_80387 + && !SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") - else if (operands[1] == constm1_rtx) - output_asm_insn (AS1 (inc%L1,%1), operands); +(define_insn "*fp_jcc_2_sse" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f#x,x#f") + (match_operand 2 "nonimmediate_operand" "f#x,xm#f")]) + (pc) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "TARGET_80387 + && SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") - else - output_asm_insn (AS2 (sub%L1,%2,%1), operands); +(define_insn "*fp_jcc_2_sse_only" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "x") + (match_operand 2 "nonimmediate_operand" "xm")]) + (pc) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "SSE_FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") - return AS1 (%J0,%l3); -}") +(define_insn "*fp_jcc_3" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "nonimmediate_operand" "fm")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) + (clobber (match_scratch:HI 4 "=a"))] + "TARGET_80387 + && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && !ix86_use_fcomi_compare (GET_CODE (operands[0])) + && SELECT_CC_MODE (GET_CODE (operands[0]), + operands[1], operands[2]) == CCFPmode + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") -(define_insn "" +(define_insn "*fp_jcc_4" [(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\"; -}") + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "nonimmediate_operand" "fm")]) + (pc) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) + (clobber (match_scratch:HI 4 "=a"))] + "TARGET_80387 + && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && !ix86_use_fcomi_compare (GET_CODE (operands[0])) + && SELECT_CC_MODE (GET_CODE (operands[0]), + operands[1], operands[2]) == CCFPmode + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") -(define_insn "" +(define_insn "*fp_jcc_5" [(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\"; -}") + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) + (clobber (match_scratch:HI 4 "=a"))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") -(define_insn "" +(define_insn "*fp_jcc_6" [(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\"; -}") + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "f") + (match_operand 2 "register_operand" "f")]) + (pc) + (label_ref (match_operand 3 "" "")))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) + (clobber (match_scratch:HI 4 "=a"))] + "TARGET_80387 + && FLOAT_MODE_P (GET_MODE (operands[1])) + && GET_MODE (operands[1]) == GET_MODE (operands[2]) + && ix86_fp_jump_nontrivial_p (GET_CODE (operands[0]))" + "#") -(define_insn "" +(define_split [(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)))] - "" - "* + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "") + (match_operand 2 "nonimmediate_operand" "")]) + (match_operand 3 "" "") + (match_operand 4 "" ""))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17))] + "reload_completed" + [(const_int 0)] { - CC_STATUS_INIT; - output_asm_insn (AS1 (dec%L0,%0), operands); - return \"jz %l1\"; -}") + ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], + operands[3], operands[4], NULL_RTX); + DONE; +}) -(define_insn "" +(define_split [(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)))] - "" - "* + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand 1 "register_operand" "") + (match_operand 2 "nonimmediate_operand" "")]) + (match_operand 3 "" "") + (match_operand 4 "" ""))) + (clobber (reg:CCFP 18)) + (clobber (reg:CCFP 17)) + (clobber (match_scratch:HI 5 "=a"))] + "reload_completed" + [(set (pc) + (if_then_else (match_dup 6) + (match_dup 3) + (match_dup 4)))] { - CC_STATUS_INIT; - output_asm_insn (AS1 (inc%L0,%0), operands); - return \"jnz %l1\"; -}") + ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2], + operands[3], operands[4], operands[5]); + DONE; +}) + +;; Unconditional and other jump instructions -(define_insn "" +(define_insn "jump" [(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)))] + (label_ref (match_operand 0 "" "")))] "" - "* -{ - CC_STATUS_INIT; - output_asm_insn (AS1 (inc%L0,%0), operands); - return \"jz %l1\"; -}") + "jmp\t%l0" + [(set_attr "type" "ibr")]) -;; 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_expand "indirect_jump" + [(set (pc) (match_operand 0 "nonimmediate_operand" "rm"))] + "" + "") -(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"))] +(define_insn "*indirect_jump" + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))] + "!TARGET_64BIT" + "jmp\t%A0" + [(set_attr "type" "ibr") + (set_attr "length_immediate" "0")]) + +(define_insn "*indirect_jump_rtx64" + [(set (pc) (match_operand:DI 0 "nonimmediate_operand" "rm"))] + "TARGET_64BIT" + "jmp\t%A0" + [(set_attr "type" "ibr") + (set_attr "length_immediate" "0")]) + +(define_expand "tablejump" + [(parallel [(set (pc) (match_operand 0 "nonimmediate_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))])] "" - "* { - rtx xops[4]; + /* In PIC mode, the table entries are stored GOT-relative. Convert + the relative address to an absolute address. */ + if (flag_pic) + { + if (TARGET_64BIT) + operands[0] = expand_simple_binop (Pmode, PLUS, operands[0], + gen_rtx_LABEL_REF (Pmode, operands[1]), + NULL_RTX, 0, + OPTAB_DIRECT); + else if (HAVE_AS_GOTOFF_IN_DATA) + { + operands[0] = expand_simple_binop (Pmode, PLUS, operands[0], + pic_offset_table_rtx, NULL_RTX, + 1, OPTAB_DIRECT); + current_function_uses_pic_offset_table = 1; + } + else + { + operands[0] = expand_simple_binop (Pmode, MINUS, pic_offset_table_rtx, + operands[0], NULL_RTX, 1, + OPTAB_DIRECT); + current_function_uses_pic_offset_table = 1; + } + } +}) - xops[0] = operands[0]; - xops[1] = operands[1]; - xops[2] = operands[2]; - xops[3] = pic_offset_table_rtx; +(define_insn "*tablejump_1" + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))] + "!TARGET_64BIT" + "jmp\t%A0" + [(set_attr "type" "ibr") + (set_attr "length_immediate" "0")]) - 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_1_rtx64" + [(set (pc) (match_operand:DI 0 "nonimmediate_operand" "rm")) + (use (label_ref (match_operand 1 "" "")))] + "TARGET_64BIT" + "jmp\t%A0" + [(set_attr "type" "ibr") + (set_attr "length_immediate" "0")]) + +;; Loop instruction +;; +;; This is all complicated by the fact that since this is a jump insn +;; we must handle our own reloads. + +(define_expand "doloop_end" + [(use (match_operand 0 "" "")) ; loop pseudo + (use (match_operand 1 "" "")) ; iterations; zero if unknown + (use (match_operand 2 "" "")) ; max iterations + (use (match_operand 3 "" "")) ; loop level + (use (match_operand 4 "" ""))] ; label + "!TARGET_64BIT && TARGET_USE_LOOP" + " +{ + /* Only use cloop on innermost loops. */ + if (INTVAL (operands[3]) > 1) + FAIL; + if (GET_MODE (operands[0]) != SImode) + FAIL; + emit_jump_insn (gen_doloop_end_internal (operands[4], operands[0], + operands[0])); + DONE; }") -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm")) - (use (label_ref (match_operand 1 "" "")))] - "" - "* +(define_insn "doloop_end_internal" + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "c,?*r,?*r") + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_operand:SI 2 "register_operand" "=1,1,*m*r") + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 3 "=X,X,r")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP" { - CC_STATUS_INIT; + if (which_alternative != 0) + return "#"; + if (get_attr_length (insn) == 2) + return "%+loop\t%l0"; + else + return "dec{l}\t%1\;%+jne\t%l0"; +} + [(set_attr "ppro_uops" "many") + (set (attr "type") + (if_then_else (and (eq_attr "alternative" "0") + (and (ge (minus (match_dup 0) (pc)) + (const_int -128)) + (lt (minus (match_dup 0) (pc)) + (const_int 124)))) + (const_string "ibr") + (const_string "multi")))]) - return AS1 (jmp,%*%0); -}") +(define_split + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "") + (const_int 1)) + (match_operand 0 "" "") + (pc))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 2 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP + && reload_completed + && REGNO (operands[1]) != 2" + [(parallel [(set (reg:CCZ 17) + (compare:CCZ (plus:SI (match_dup 1) (const_int -1)) + (const_int 0))) + (set (match_dup 1) (plus:SI (match_dup 1) (const_int -1)))]) + (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0)) + (match_dup 0) + (pc)))] + "") + +(define_split + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "register_operand" "") + (const_int 1)) + (match_operand 0 "" "") + (pc))) + (set (match_operand:SI 2 "nonimmediate_operand" "") + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (match_scratch:SI 3 "")) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_USE_LOOP + && reload_completed + && (! REG_P (operands[2]) + || ! rtx_equal_p (operands[1], operands[2]))" + [(set (match_dup 3) (match_dup 1)) + (parallel [(set (reg:CCZ 17) + (compare:CCZ (plus:SI (match_dup 3) (const_int -1)) + (const_int 0))) + (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))]) + (set (match_dup 2) (match_dup 3)) + (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0)) + (match_dup 0) + (pc)))] + "") -;; Call insns. +;; Convert setcc + movzbl to xor + setcc if operands don't overlap. + +(define_peephole2 + [(set (reg 17) (match_operand 0 "" "")) + (set (match_operand:QI 1 "register_operand" "") + (match_operator:QI 2 "ix86_comparison_operator" + [(reg 17) (const_int 0)])) + (set (match_operand 3 "q_regs_operand" "") + (zero_extend (match_dup 1)))] + "(peep2_reg_dead_p (3, operands[1]) + || operands_match_p (operands[1], operands[3])) + && ! reg_overlap_mentioned_p (operands[3], operands[0])" + [(set (match_dup 4) (match_dup 0)) + (set (strict_low_part (match_dup 5)) + (match_dup 2))] +{ + operands[4] = gen_rtx_REG (GET_MODE (operands[0]), 17); + operands[5] = gen_rtx_REG (QImode, REGNO (operands[3])); + ix86_expand_clear (operands[3]); +}) + +;; Similar, but match zero_extendhisi2_and, which adds a clobber. + +(define_peephole2 + [(set (reg 17) (match_operand 0 "" "")) + (set (match_operand:QI 1 "register_operand" "") + (match_operator:QI 2 "ix86_comparison_operator" + [(reg 17) (const_int 0)])) + (parallel [(set (match_operand 3 "q_regs_operand" "") + (zero_extend (match_dup 1))) + (clobber (reg:CC 17))])] + "(peep2_reg_dead_p (3, operands[1]) + || operands_match_p (operands[1], operands[3])) + && ! reg_overlap_mentioned_p (operands[3], operands[0])" + [(set (match_dup 4) (match_dup 0)) + (set (strict_low_part (match_dup 5)) + (match_dup 2))] +{ + operands[4] = gen_rtx_REG (GET_MODE (operands[0]), 17); + operands[5] = gen_rtx_REG (QImode, REGNO (operands[3])); + ix86_expand_clear (operands[3]); +}) + +;; Call instructions. -;; 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. +;; The predicates normally associated with named expanders are not properly +;; checked for calls. This is a bug in the generic code, but it isn't that +;; easy to fix. Ignore it for now and be prepared to fix things up. ;; Call subroutine returning no value. (define_expand "call_pop" - [(parallel [(call (match_operand:QI 0 "indirect_operand" "") - (match_operand:SI 1 "general_operand" "")) + [(parallel [(call (match_operand:QI 0 "" "") + (match_operand:SI 1 "" "")) (set (reg:SI 7) (plus:SI (reg:SI 7) - (match_operand:SI 3 "immediate_operand" "")))])] - "" - " + (match_operand:SI 3 "" "")))])] + "!TARGET_64BIT" { - rtx addr; - if (operands[3] == const0_rtx) { - emit_insn (gen_call (operands[0], operands[1])); + emit_insn (gen_call (operands[0], operands[1], constm1_rtx)); DONE; } - - if (flag_pic) + /* Static functions and indirect calls don't need + current_function_uses_pic_offset_table. */ + if (flag_pic + && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF + && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0))) 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")) + if (! call_insn_operand (XEXP (operands[0], 0), Pmode)) + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + if (TARGET_64BIT) + abort(); +}) + +(define_insn "*call_pop_0" + [(call (mem:QI (match_operand:SI 0 "constant_call_address_operand" "")) + (match_operand:SI 1 "" "")) (set (reg:SI 7) (plus:SI (reg:SI 7) - (match_operand:SI 3 "immediate_operand" "i")))] - "" - "* + (match_operand:SI 2 "immediate_operand" "")))] + "!TARGET_64BIT" +{ + if (SIBLING_CALL_P (insn)) + return "jmp\t%P0"; + else + return "call\t%P0"; +} + [(set_attr "type" "call")]) + +(define_insn "*call_pop_1" + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) + (match_operand:SI 1 "" "")) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 2 "immediate_operand" "i")))] + "!TARGET_64BIT" { - if (GET_CODE (operands[0]) == MEM - && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + if (constant_call_address_operand (operands[0], Pmode)) { - operands[0] = XEXP (operands[0], 0); - return AS1 (call,%*%0); + if (SIBLING_CALL_P (insn)) + return "jmp\t%P0"; + else + return "call\t%P0"; } + if (SIBLING_CALL_P (insn)) + return "jmp\t%A0"; 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") + return "call\t%A0"; +} + [(set_attr "type" "call")]) (define_expand "call" - [(call (match_operand:QI 0 "indirect_operand" "") - (match_operand:SI 1 "general_operand" ""))] + [(call (match_operand:QI 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))] ;; Operand 1 not used on the i386. "" - " { - rtx addr; - - if (flag_pic) + rtx insn; + /* Static functions and indirect calls don't need + current_function_uses_pic_offset_table. */ + if (flag_pic + && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF + && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0))) 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 (! call_insn_operand (XEXP (operands[0], 0), Pmode)) + XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + if (TARGET_64BIT && INTVAL (operands[2]) >= 0) + { + rtx reg = gen_rtx_REG (QImode, 0); + emit_move_insn (reg, operands[2]); + insn = emit_call_insn (gen_call_exp (operands[0], operands[1])); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg); + DONE; + } + insn = emit_call_insn (gen_call_exp (operands[0], operands[1])); + DONE; +}) - 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_expand "call_exp" + [(call (match_operand:QI 0 "" "") + (match_operand 1 "" ""))] + "" + "") -(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. +(define_insn "*call_0" + [(call (mem:QI (match_operand 0 "constant_call_address_operand" "")) + (match_operand 1 "" ""))] "" - "* { - if (GET_CODE (operands[0]) == MEM - && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + if (SIBLING_CALL_P (insn)) + return "jmp\t%P0"; + else + return "call\t%P0"; +} + [(set_attr "type" "call")]) + +(define_insn "*call_1" + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) + (match_operand 1 "" ""))] + "!TARGET_64BIT" +{ + if (constant_call_address_operand (operands[0], QImode)) { - operands[0] = XEXP (operands[0], 0); - return AS1 (call,%*%0); + if (SIBLING_CALL_P (insn)) + return "jmp\t%P0"; + else + return "call\t%P0"; } + if (SIBLING_CALL_P (insn)) + return "jmp\t%A0"; 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") + return "call\t%A0"; +} + [(set_attr "type" "call")]) + +(define_insn "*call_1_rex64" + [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm")) + (match_operand 1 "" ""))] + "TARGET_64BIT" +{ + if (constant_call_address_operand (operands[0], QImode)) + { + if (SIBLING_CALL_P (insn)) + return "jmp\t%P0"; + else + return "call\t%P0"; + } + if (SIBLING_CALL_P (insn)) + return "jmp\t%A0"; + else + return "call\t%A0"; +} + [(set_attr "type" "call")]) ;; 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" ""))) + (call (match_operand:QI 1 "" "") + (match_operand:SI 2 "" ""))) (set (reg:SI 7) (plus:SI (reg:SI 7) - (match_operand:SI 4 "immediate_operand" "")))])] - "" - " + (match_operand:SI 4 "" "")))])] + "!TARGET_64BIT" { - rtx addr; - if (operands[4] == const0_rtx) { - emit_insn (gen_call_value (operands[0], operands[1], operands[2])); + emit_insn (gen_call_value (operands[0], operands[1], operands[2], + constm1_rtx)); DONE; } - - if (flag_pic) + /* Static functions and indirect calls don't need + current_function_uses_pic_offset_table. */ + if (flag_pic + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0))) 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") + if (! call_insn_operand (XEXP (operands[1], 0), Pmode)) + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); +}) (define_expand "call_value" [(set (match_operand 0 "" "") - (call (match_operand:QI 1 "indirect_operand" "") - (match_operand:SI 2 "general_operand" "")))] + (call (match_operand:QI 1 "" "") + (match_operand:SI 2 "" ""))) + (use (match_operand:SI 3 "" ""))] ;; Operand 2 not used on the i386. "" - " { - rtx addr; - - if (flag_pic) + rtx insn; + /* Static functions and indirect calls don't need + current_function_uses_pic_offset_table. */ + if (flag_pic + && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0))) 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))) + if (! call_insn_operand (XEXP (operands[1], 0), Pmode)) + XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + if (TARGET_64BIT && INTVAL (operands[3]) >= 0) { - operands[1] = XEXP (operands[1], 0); - output_asm_insn (AS1 (call,%*%1), operands); + rtx reg = gen_rtx_REG (QImode, 0); + emit_move_insn (reg, operands[3]); + insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1], + operands[2])); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg); + DONE; } - else - output_asm_insn (AS1 (call,%P1), operands); - - RET; -}") + insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1], + operands[2])); + DONE; +}) -(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") +(define_expand "call_value_exp" + [(set (match_operand 0 "" "") + (call (match_operand:QI 1 "" "") + (match_operand:SI 2 "" "")))] + "" + "") ;; Call subroutine returning any type. @@ -6888,7 +13531,6 @@ byte_xor_operation: (match_operand 1 "" "") (match_operand 2 "" "")])] "" - " { int i; @@ -6899,8 +13541,10 @@ byte_xor_operation: 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)); + operands[0], const0_rtx, + GEN_INT (SSE_REGPARM_MAX - 1)) + : gen_call (operands[0], const0_rtx, + GEN_INT (SSE_REGPARM_MAX - 1))); for (i = 0; i < XVECLEN (operands[2], 0); i++) { @@ -6915,7 +13559,9 @@ byte_xor_operation: emit_insn (gen_blockage ()); DONE; -}") +}) + +;; Prologue and epilogue instructions ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and ;; all of memory. This blocks insns from being moved across this point. @@ -6924,827 +13570,2252 @@ byte_xor_operation: [(unspec_volatile [(const_int 0)] 0)] "" "" - [(set_attr "memory" "none")]) + [(set_attr "length" "0")]) ;; 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. +;; See comments for ix86_can_use_return_insn_p in i386.c. (define_expand "return" [(return)] "ix86_can_use_return_insn_p ()" - "") +{ + if (current_function_pops_args) + { + rtx popc = GEN_INT (current_function_pops_args); + emit_jump_insn (gen_return_pop_internal (popc)); + DONE; + } +}) (define_insn "return_internal" [(return)] "reload_completed" "ret" - [(set_attr "memory" "none")]) + [(set_attr "length" "1") + (set_attr "length_immediate" "0") + (set_attr "modrm" "0")]) (define_insn "return_pop_internal" [(return) (use (match_operand:SI 0 "const_int_operand" ""))] "reload_completed" - "ret %0" - [(set_attr "memory" "none")]) + "ret\t%0" + [(set_attr "length" "3") + (set_attr "length_immediate" "2") + (set_attr "modrm" "0")]) + +(define_insn "return_indirect_internal" + [(return) + (use (match_operand:SI 0 "register_operand" "r"))] + "reload_completed" + "jmp\t%A0" + [(set_attr "type" "ibr") + (set_attr "length_immediate" "0")]) (define_insn "nop" [(const_int 0)] "" "nop" - [(set_attr "memory" "none")]) + [(set_attr "length" "1") + (set_attr "length_immediate" "0") + (set_attr "modrm" "0") + (set_attr "ppro_uops" "one")]) (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")]) + "ix86_expand_prologue (); DONE;") (define_insn "prologue_set_got" - [(set (match_operand:SI 0 "" "") - (unspec_volatile + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(plus:SI (match_dup 0) (plus:SI (match_operand:SI 1 "symbolic_operand" "") - (minus:SI (pc) (match_operand 2 "" ""))))] 1))] - "" - "* + (minus:SI (pc) (match_operand 2 "" ""))))] 1)) + (clobber (reg:CC 17))] + "!TARGET_64BIT" { - char buffer[64]; - + if (GET_CODE (operands[2]) == LABEL_REF) + operands[2] = XEXP (operands[2], 0); if (TARGET_DEEP_BRANCH_PREDICTION) - { - sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0)); - output_asm_insn (buffer, operands); - } + return "add{l}\t{%1, %0|%0, %1}"; else - { - sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0)); - output_asm_insn (buffer, operands); - } - RET; -}") + return "add{l}\t{%1+[.-%X2], %0|%0, %a1+(.-%X2)}"; +} + [(set_attr "type" "alu") + ; Since this insn may have two constant operands, we must set the + ; length manually. + (set_attr "length_immediate" "4") + (set_attr "mode" "SI")]) (define_insn "prologue_get_pc" - [(set (match_operand:SI 0 "" "") - (unspec_volatile [(plus:SI (pc) (match_operand 1 "" ""))] 2))] - "" - "* + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(plus:SI (pc) (match_operand 1 "" ""))] 2))] + "!TARGET_64BIT" { - output_asm_insn (AS1 (call,%X1), operands); - if (! TARGET_DEEP_BRANCH_PREDICTION) + if (GET_CODE (operands[1]) == LABEL_REF) + operands[1] = XEXP (operands[1], 0); + output_asm_insn ("call\t%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); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (operands[1])); + } RET; -}" - [(set_attr "memory" "none")]) +} + [(set_attr "type" "multi")]) (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]; + "ix86_expand_epilogue (1); DONE;") - 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))] +(define_expand "sibcall_epilogue" + [(const_int 1)] "" - "leave" - [(set_attr "memory" "none")]) + "ix86_expand_epilogue (0); DONE;") -(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)))] +(define_expand "eh_return" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "register_operand" ""))] "" - "* { - 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; + rtx tmp, sa = operands[0], ra = operands[1]; + + /* Tricky bit: we write the address of the handler to which we will + be returning into someone else's stack frame, one word below the + stack address we wish to restore. */ + tmp = gen_rtx_PLUS (Pmode, arg_pointer_rtx, sa); + tmp = plus_constant (tmp, -UNITS_PER_WORD); + tmp = gen_rtx_MEM (Pmode, tmp); + emit_move_insn (tmp, ra); + + if (Pmode == SImode) + emit_insn (gen_eh_return_si (sa)); + else + emit_insn (gen_eh_return_di (sa)); + emit_barrier (); + DONE; +}) - operands[0] = change_address (operands[0], VOIDmode, addr0); - operands[1] = change_address (operands[1], VOIDmode, addr1); -}") +(define_insn_and_split "eh_return_si" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "c")] 13)] + "!TARGET_64BIT" + "#" + "reload_completed" + [(const_int 1)] + "ix86_expand_epilogue (2); DONE;") -;; 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_and_split "eh_return_di" + [(unspec_volatile [(match_operand:DI 0 "register_operand" "c")] 13)] + "TARGET_64BIT" + "#" + "reload_completed" + [(const_int 1)] + "ix86_expand_epilogue (2); DONE;") -(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))] +(define_insn "leave" + [(set (reg:SI 7) (plus:SI (reg:SI 6) (const_int 4))) + (set (reg:SI 6) (mem:SI (reg:SI 6))) + (clobber (mem:BLK (scratch)))] + "!TARGET_64BIT" + "leave" + [(set_attr "length_immediate" "0") + (set_attr "length" "1") + (set_attr "modrm" "0") + (set_attr "modrm" "0") + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + +(define_insn "leave_rex64" + [(set (reg:DI 7) (plus:DI (reg:DI 6) (const_int 8))) + (set (reg:DI 6) (mem:DI (reg:DI 6))) + (clobber (mem:BLK (scratch)))] + "TARGET_64BIT" + "leave" + [(set_attr "length_immediate" "0") + (set_attr "length" "1") + (set_attr "modrm" "0") + (set_attr "modrm" "0") + (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + +(define_expand "ffssi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ffs:SI (match_operand:SI 1 "general_operand" "")))] "" - "* { - rtx xops[2]; + rtx out = gen_reg_rtx (SImode), tmp = gen_reg_rtx (SImode); + rtx in = operands[1]; - output_asm_insn (\"cld\", operands); - if (GET_CODE (operands[2]) == CONST_INT) + if (TARGET_CMOVE) { - 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); + emit_move_insn (tmp, constm1_rtx); + emit_insn (gen_ffssi_1 (out, in)); + emit_insn (gen_rtx_SET (VOIDmode, out, + gen_rtx_IF_THEN_ELSE (SImode, + gen_rtx_EQ (VOIDmode, gen_rtx_REG (CCZmode, FLAGS_REG), + const0_rtx), + tmp, + out))); + emit_insn (gen_addsi3 (out, out, const1_rtx)); + emit_move_insn (operands[0], out); } - 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) + /* Pentium bsf instruction is extremly slow. The following code is + recommended by the Intel Optimizing Manual as a reasonable replacement: + TEST EAX,EAX + JZ SHORT BS2 + XOR ECX,ECX + MOV DWORD PTR [TEMP+4],ECX + SUB ECX,EAX + AND EAX,ECX + MOV DWORD PTR [TEMP],EAX + FILD QWORD PTR [TEMP] + FSTP QWORD PTR [TEMP] + WAIT ; WAIT only needed for compatibility with + ; earlier processors + MOV ECX, DWORD PTR [TEMP+4] + SHR ECX,20 + SUB ECX,3FFH + TEST EAX,EAX ; clear zero flag + BS2: + Following piece of code expand ffs to similar beast. + */ + + else if (TARGET_PENTIUM && !optimize_size && TARGET_80387) { - 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); + rtx label = gen_label_rtx (); + rtx lo, hi; + rtx mem = assign_386_stack_local (DImode, 0); + rtx fptmp = gen_reg_rtx (DFmode); + split_di (&mem, 1, &lo, &hi); + + emit_move_insn (out, const0_rtx); + + emit_cmp_and_jump_insns (in, const0_rtx, EQ, 0, SImode, 1, label); + + emit_move_insn (hi, out); + emit_insn (gen_subsi3 (out, out, in)); + emit_insn (gen_andsi3 (out, out, in)); + emit_move_insn (lo, out); + emit_insn (gen_floatdidf2 (fptmp,mem)); + emit_move_insn (gen_rtx_MEM (DFmode, XEXP (mem, 0)), fptmp); + emit_move_insn (out, hi); + emit_insn (gen_lshrsi3 (out, out, GEN_INT (20))); + emit_insn (gen_subsi3 (out, out, GEN_INT (0x3ff - 1))); + + emit_label (label); + LABEL_NUSES (label) = 1; + + emit_move_insn (operands[0], out); } 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; -}") + { + emit_move_insn (tmp, const0_rtx); + emit_insn (gen_ffssi_1 (out, in)); + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_STRICT_LOW_PART (VOIDmode, gen_lowpart (QImode, tmp)), + gen_rtx_EQ (QImode, gen_rtx_REG (CCZmode, FLAGS_REG), + const0_rtx))); + emit_insn (gen_negsi2 (tmp, tmp)); + emit_insn (gen_iorsi3 (out, out, tmp)); + emit_insn (gen_addsi3 (out, out, const1_rtx)); + emit_move_insn (operands[0], out); + } + DONE; +}) -(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))] +(define_insn "ffssi_1" + [(set (reg:CCZ 17) + (compare:CCZ (match_operand:SI 1 "nonimmediate_operand" "rm") + (const_int 0))) + (set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_dup 1)] 5))] "" - "* -{ - rtx xops[2]; - - cc_status.flags |= CC_NOT_SIGNED; + "bsf{l}\t{%1, %0|%0, %1}" + [(set_attr "prefix_0f" "1") + (set_attr "ppro_uops" "few")]) - xops[0] = gen_rtx_REG (QImode, 0); - xops[1] = CONST0_RTX (QImode); +;; ffshi2 is not useful -- 4 word prefix ops are needed, which is larger +;; and slower than the two-byte movzx insn needed to do the work in SImode. + +;; 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. The conversion may be SFmode or +;; SImode if the target mode DFmode, but only SImode if the target mode +;; is SFmode. - output_asm_insn (\"cld\", operands); - output_asm_insn (AS2 (test%B0,%1,%0), xops); - return \"repz\;cmps%B2\"; -}") +;; Gcc is slightly more smart about handling normal two address instructions +;; so use special patterns for add and mull. +(define_insn "*fop_sf_comm_nosse" + [(set (match_operand:SF 0 "register_operand" "=f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonimmediate_operand" "fm")]))] + "TARGET_80387 && !TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_sf_comm" + [(set (match_operand:SF 0 "register_operand" "=f#x,x#f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "register_operand" "%0,0") + (match_operand:SF 2 "nonimmediate_operand" "fm#x,xm#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (eq_attr "alternative" "1") + (const_string "sse") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop")))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_sf_comm_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "register_operand" "%0") + (match_operand:SF 2 "nonimmediate_operand" "xm")]))] + "TARGET_SSE_MATH && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) - -;; 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_insn "*fop_df_comm_nosse" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "nonimmediate_operand" "fm")]))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_df_comm" + [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "fm#Y,Ym#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_SSE2 && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (eq_attr "alternative" "1") + (const_string "sse") + (if_then_else (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop")))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_df_comm_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "%0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")]))] + "TARGET_SSE2 && TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) -(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); +(define_insn "*fop_xf_comm" + [(set (match_operand:XF 0 "register_operand" "=f") + (match_operator:XF 3 "binary_fp_operator" + [(match_operand:XF 1 "register_operand" "%0") + (match_operand:XF 2 "register_operand" "f")]))] + "!TARGET_64BIT && TARGET_80387 + && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "XF")]) + +(define_insn "*fop_tf_comm" + [(set (match_operand:TF 0 "register_operand" "=f") + (match_operator:TF 3 "binary_fp_operator" + [(match_operand:TF 1 "register_operand" "%0") + (match_operand:TF 2 "register_operand" "f")]))] + "TARGET_80387 && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (if_then_else (match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (const_string "fop"))) + (set_attr "mode" "XF")]) - 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); +(define_insn "*fop_sf_1_nosse" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "nonimmediate_operand" "0,fm") + (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387 && !TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:SF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_sf_1" + [(set (match_operand:SF 0 "register_operand" "=f,f,x") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "nonimmediate_operand" "0,fm,0") + (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm#f")]))] + "TARGET_80387 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "sse") + (match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:SF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_sf_1_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonimmediate_operand" "xm")]))] + "TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" + "* return output_387_binary_op (insn, operands);" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) - if (temp != operands[0]) - emit_move_insn (operands[0], temp); - DONE; -}") +;; ??? Add SSE splitters for these! +(define_insn "*fop_sf_2" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (match_operator:SF 3 "binary_fp_operator" + [(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) + (match_operand:SF 2 "register_operand" "0,0")]))] + "TARGET_80387 && TARGET_USE_FIOP && !TARGET_SSE_MATH" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:SF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(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_insn "*fop_sf_3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (match_operator:SF 3 "binary_fp_operator" + [(match_operand:SF 1 "register_operand" "0,0") + (float:SF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP && !TARGET_SSE_MATH" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:SF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:SF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(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); +(define_insn "*fop_df_1_nosse" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "nonimmediate_operand" "0,fm") + (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "DF")]) + + +(define_insn "*fop_df_1" + [(set (match_operand:DF 0 "register_operand" "=f#Y,f#Y,Y#f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "nonimmediate_operand" "0,fm,0") + (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym#f")]))] + "TARGET_80387 && TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c' + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "sse") + (match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_df_1_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")]))] + "TARGET_SSE2 && TARGET_SSE_MATH + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" + "* return output_387_binary_op (insn, operands);" + [(set_attr "type" "sse")]) - 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); +;; ??? Add SSE splitters for these! +(define_insn "*fop_df_2" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_fp_operator" + [(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) + (match_operand:DF 2 "register_operand" "0,0")]))] + "TARGET_80387 && TARGET_USE_FIOP && !(TARGET_SSE2 && TARGET_SSE_MATH)" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) - if (temp != operands[0]) - emit_move_insn (operands[0], temp); - DONE; -}") +(define_insn "*fop_df_3" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "0,0") + (float:DF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP && !(TARGET_SSE2 && TARGET_SSE_MATH)" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "ppro_uops" "many") + (set_attr "mode" "SI")]) -(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 "*fop_df_4" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (match_operator:DF 3 "binary_fp_operator" + [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:DF 2 "register_operand" "0,f")]))] + "TARGET_80387 && (!TARGET_SSE2 || !TARGET_SSE_MATH) + && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "SF")]) -(define_insn "" +(define_insn "*fop_df_5" [(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" + (match_operator:DF 3 "binary_fp_operator" + [(match_operand:DF 1 "register_operand" "0,f") + (float_extend:DF + (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] + "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH)" "* 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") + (cond [(match_operand:DF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:DF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "SF")]) -(define_insn "" +(define_insn "*fop_xf_1" [(set (match_operand:XF 0 "register_operand" "=f,f") - (match_operator:XF 3 "binary_387_op" + (match_operator:XF 3 "binary_fp_operator" [(match_operand:XF 1 "register_operand" "0,f") (match_operand:XF 2 "register_operand" "f,0")]))] - "TARGET_80387" + "!TARGET_64BIT && TARGET_80387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "XF")]) + +(define_insn "*fop_tf_1" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(match_operand:TF 1 "register_operand" "0,f") + (match_operand:TF 2 "register_operand" "f,0")]))] + "TARGET_80387 + && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'" "* 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") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "XF")]) -(define_insn "" +(define_insn "*fop_xf_2" [(set (match_operand:XF 0 "register_operand" "=f,f") - (match_operator:XF 3 "binary_387_op" + (match_operator:XF 3 "binary_fp_operator" + [(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) + (match_operand:XF 2 "register_operand" "0,0")]))] + "!TARGET_64BIT && TARGET_80387 && TARGET_USE_FIOP" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) + +(define_insn "*fop_tf_2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(float:TF (match_operand:SI 1 "nonimmediate_operand" "m,?r")) + (match_operand:TF 2 "register_operand" "0,0")]))] + "TARGET_80387 && TARGET_USE_FIOP" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) + +(define_insn "*fop_xf_3" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_fp_operator" + [(match_operand:XF 1 "register_operand" "0,0") + (float:XF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "!TARGET_64BIT && TARGET_80387 && TARGET_USE_FIOP" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) + +(define_insn "*fop_tf_3" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(match_operand:TF 1 "register_operand" "0,0") + (float:TF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))] + "TARGET_80387 && TARGET_USE_FIOP" + "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "fp_int_src" "true") + (set_attr "mode" "SI") + (set_attr "ppro_uops" "many")]) + +(define_insn "*fop_xf_4" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_fp_operator" [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) (match_operand:XF 2 "register_operand" "0,f")]))] + "!TARGET_64BIT && TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_tf_4" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:TF 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") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "SF")]) -(define_insn "" +(define_insn "*fop_xf_5" [(set (match_operand:XF 0 "register_operand" "=f,f") - (match_operator:XF 3 "binary_387_op" + (match_operator:XF 3 "binary_fp_operator" [(match_operand:XF 1 "register_operand" "0,f") (float_extend:XF (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] - "TARGET_80387" + "!TARGET_64BIT && 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") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") ] - (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")]))] + (const_string "fop"))) + (set_attr "mode" "SF")]) + +(define_insn "*fop_tf_5" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(match_operand:TF 1 "register_operand" "0,f") + (float_extend:TF + (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") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "SF")]) -(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"))]))] +(define_insn "*fop_xf_6" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_fp_operator" + [(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,0")) + (match_operand:XF 2 "register_operand" "0,f")]))] + "!TARGET_64BIT && TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_tf_6" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "fm,0")) + (match_operand:TF 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") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "DF")]) -(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")]))] +(define_insn "*fop_xf_7" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_fp_operator" + [(match_operand:XF 1 "register_operand" "0,f") + (float_extend:XF + (match_operand:DF 2 "nonimmediate_operand" "fm,0"))]))] + "!TARGET_64BIT && TARGET_80387" + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:XF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:XF 3 "div_operator" "") + (const_string "fdiv") + ] + (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_insn "*fop_tf_7" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (match_operator:TF 3 "binary_fp_operator" + [(match_operand:TF 1 "register_operand" "0,f") + (float_extend:TF + (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") + (cond [(match_operand:TF 3 "mult_operator" "") + (const_string "fmul") + (match_operand:TF 3 "div_operator" "") + (const_string "fdiv") ] - (const_string "fpop") - ) - )]) + (const_string "fop"))) + (set_attr "mode" "DF")]) + +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operator 3 "binary_fp_operator" + [(float (match_operand:SI 1 "register_operand" "")) + (match_operand 2 "register_operand" "")]))] + "TARGET_80387 && reload_completed + && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(const_int 0)] +{ + operands[4] = ix86_force_to_memory (GET_MODE (operands[1]), operands[1]); + operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_fmt_ee (GET_CODE (operands[3]), + GET_MODE (operands[3]), + operands[4], + operands[2]))); + ix86_free_from_memory (GET_MODE (operands[1])); + DONE; +}) + +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operator 3 "binary_fp_operator" + [(match_operand 1 "register_operand" "") + (float (match_operand:SI 2 "register_operand" ""))]))] + "TARGET_80387 && reload_completed + && FLOAT_MODE_P (GET_MODE (operands[0]))" + [(const_int 0)] +{ + operands[4] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]); + operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_fmt_ee (GET_CODE (operands[3]), + GET_MODE (operands[3]), + operands[1], + operands[4]))); + ix86_free_from_memory (GET_MODE (operands[2])); + DONE; +}) -(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)))] +;; FPU special functions. + +(define_expand "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "")))] + "(! TARGET_NO_FANCY_MATH_387 && TARGET_80387) || TARGET_SSE_MATH" +{ + if (!TARGET_SSE_MATH) + operands[1] = force_reg (SFmode, operands[1]); +}) + +(define_insn "sqrtsf2_1" + [(set (match_operand:SF 0 "register_operand" "=f#x,x#f") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0#x,xm#f")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_SSE_MATH && TARGET_MIX_SSE_I387)" + "@ + fsqrt + sqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "fpspc,sse") + (set_attr "mode" "SF,SF") + (set_attr "athlon_decode" "direct,*")]) + +(define_insn "sqrtsf2_1_sse_only" + [(set (match_operand:SF 0 "register_operand" "=x") + (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE_MATH && (!TARGET_80387 || !TARGET_MIX_SSE_I387)" + "sqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "SF") + (set_attr "athlon_decode" "*")]) + +(define_insn "sqrtsf2_i387" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && !TARGET_SSE_MATH" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF") + (set_attr "athlon_decode" "direct")]) + +(define_expand "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "")))] + "(! TARGET_NO_FANCY_MATH_387 && TARGET_80387) + || (TARGET_SSE2 && TARGET_SSE_MATH)" +{ + if (!TARGET_SSE2 || !TARGET_SSE_MATH) + operands[1] = force_reg (DFmode, operands[1]); +}) + +(define_insn "sqrtdf2_1" + [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0#Y,Ym#f")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387)" + "@ + fsqrt + sqrtsd\t{%1, %0|%0, %1}" + [(set_attr "type" "fpspc,sse") + (set_attr "mode" "DF,DF") + (set_attr "athlon_decode" "direct,*")]) + +(define_insn "sqrtdf2_1_sse_only" + [(set (match_operand:DF 0 "register_operand" "=Y") + (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2 && TARGET_SSE_MATH && (!TARGET_80387 || !TARGET_MIX_SSE_I387)" + "sqrtsd\t{%1, %0|%0, %1}" + [(set_attr "type" "sse") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "*")]) + +(define_insn "sqrtdf2_i387" + [(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_SSE2 || !TARGET_SSE_MATH)" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "*sqrtextendsfdf2" + [(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 + && !(TARGET_SSE2 && TARGET_SSE_MATH)" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "register_operand" "0")))] + "!TARGET_64BIT && TARGET_80387 && !TARGET_NO_FANCY_MATH_387 + && (TARGET_IEEE_FP || flag_unsafe_math_optimizations) " + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "sqrttf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (sqrt:TF (match_operand:TF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_unsafe_math_optimizations) " + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "*sqrtextenddfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387 && TARGET_NO_FANCY_MATH_387" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "*sqrtextenddftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (sqrt:TF (float_extend:TF + (match_operand:DF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "*sqrtextendsfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "!TARGET_64BIT && TARGET_80387 && TARGET_NO_FANCY_MATH_387" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(define_insn "*sqrtextendsftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (sqrt:TF (float_extend:TF + (match_operand:SF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" + "fsqrt" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF") + (set_attr "athlon_decode" "direct")]) + +(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_unsafe_math_optimizations" + "fsin" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(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_unsafe_math_optimizations" + "fsin" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF")]) + +(define_insn "*sinextendsfdf2" + [(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_unsafe_math_optimizations" + "fsin" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(define_insn "sinxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))] + "!TARGET_64BIT && TARGET_80387 && TARGET_NO_FANCY_MATH_387 + && flag_unsafe_math_optimizations" + "fsin" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF")]) + +(define_insn "sintf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (unspec:TF [(match_operand:TF 1 "register_operand" "0")] 1))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fsin" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF")]) + +(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_unsafe_math_optimizations" + "fcos" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(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_unsafe_math_optimizations" + "fcos" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF")]) + +(define_insn "*cosextendsfdf2" + [(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_unsafe_math_optimizations" + "fcos" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(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_unsafe_math_optimizations" + "fcos" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF")]) + +(define_insn "costf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (unspec:TF [(match_operand:TF 1 "register_operand" "0")] 2))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fcos" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF")]) + +;; Block operation instructions + +(define_insn "cld" + [(set (reg:SI 19) (const_int 0))] + "" + "cld" + [(set_attr "type" "cld")]) + +(define_expand "movstrsi" + [(use (match_operand:BLK 0 "memory_operand" "")) + (use (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:SI 2 "nonmemory_operand" "")) + (use (match_operand:SI 3 "const_int_operand" ""))] "" - " { - 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)); + if (ix86_expand_movstr (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}) + +(define_expand "movstrdi" + [(use (match_operand:BLK 0 "memory_operand" "")) + (use (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:DI 2 "nonmemory_operand" "")) + (use (match_operand:DI 3 "const_int_operand" ""))] + "TARGET_64BIT" +{ + if (ix86_expand_movstr (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}) + +;; Most CPUs don't like single string operations +;; Handle this case here to simplify previous expander. + +(define_expand "strmovdi_rex64" + [(set (match_dup 2) + (mem:DI (match_operand:DI 1 "register_operand" ""))) + (set (mem:DI (match_operand:DI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 8))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:DI (match_dup 1) (const_int 8))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovdi_rex_1 (operands[0], operands[1], operands[0], + operands[1])); DONE; } + else + operands[2] = gen_reg_rtx (DImode); +}) - 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_expand "strmovsi" + [(set (match_dup 2) + (mem:SI (match_operand:SI 1 "register_operand" ""))) + (set (mem:SI (match_operand:SI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 4))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 4))) + (clobber (reg:CC 17))])] + "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_strmovsi_rex64 (operands[0], operands[1])); + DONE; + } + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovsi_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (SImode); +}) + +(define_expand "strmovsi_rex64" + [(set (match_dup 2) + (mem:SI (match_operand:DI 1 "register_operand" ""))) + (set (mem:SI (match_operand:DI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 4))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:DI (match_dup 1) (const_int 4))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovsi_rex_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (SImode); +}) -(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))] +(define_expand "strmovhi" + [(set (match_dup 2) + (mem:HI (match_operand:SI 1 "register_operand" ""))) + (set (mem:HI (match_operand:SI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 2))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 2))) + (clobber (reg:CC 17))])] "" - "* { - rtx xops[2]; + if (TARGET_64BIT) + { + emit_insn (gen_strmovhi_rex64 (operands[0], operands[1])); + DONE; + } + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovhi_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (HImode); +}) + +(define_expand "strmovhi_rex64" + [(set (match_dup 2) + (mem:HI (match_operand:DI 1 "register_operand" ""))) + (set (mem:HI (match_operand:DI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 2))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:DI (match_dup 1) (const_int 2))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovhi_rex_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (HImode); +}) - 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\"; -}") +(define_expand "strmovqi" + [(set (match_dup 2) + (mem:QI (match_operand:SI 1 "register_operand" ""))) + (set (mem:QI (match_operand:SI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 1))) + (clobber (reg:CC 17))])] + "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_strmovqi_rex64 (operands[0], operands[1])); + DONE; + } + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovqi_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (QImode); +}) -/* Conditional move define_insns. */ +(define_expand "strmovqi_rex64" + [(set (match_dup 2) + (mem:QI (match_operand:DI 1 "register_operand" ""))) + (set (mem:QI (match_operand:DI 0 "register_operand" "")) + (match_dup 2)) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 1))) + (clobber (reg:CC 17))]) + (parallel [(set (match_dup 1) (plus:DI (match_dup 1) (const_int 1))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strmovqi_rex_1 (operands[0], operands[1], operands[0], + operands[1])); + DONE; + } + else + operands[2] = gen_reg_rtx (QImode); +}) + +(define_insn "strmovdi_rex_1" + [(set (mem:DI (match_operand:DI 2 "register_operand" "0")) + (mem:DI (match_operand:DI 3 "register_operand" "1"))) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 2) + (const_int 8))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (match_dup 3) + (const_int 8))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "movsq" + [(set_attr "type" "str") + (set_attr "mode" "DI") + (set_attr "memory" "both")]) + +(define_insn "strmovsi_1" + [(set (mem:SI (match_operand:SI 2 "register_operand" "0")) + (mem:SI (match_operand:SI 3 "register_operand" "1"))) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 2) + (const_int 4))) + (set (match_operand:SI 1 "register_operand" "=S") + (plus:SI (match_dup 3) + (const_int 4))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "{movsl|movsd}" + [(set_attr "type" "str") + (set_attr "mode" "SI") + (set_attr "memory" "both")]) + +(define_insn "strmovsi_rex_1" + [(set (mem:SI (match_operand:DI 2 "register_operand" "0")) + (mem:SI (match_operand:DI 3 "register_operand" "1"))) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 2) + (const_int 4))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (match_dup 3) + (const_int 4))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "{movsl|movsd}" + [(set_attr "type" "str") + (set_attr "mode" "SI") + (set_attr "memory" "both")]) + +(define_insn "strmovhi_1" + [(set (mem:HI (match_operand:SI 2 "register_operand" "0")) + (mem:HI (match_operand:SI 3 "register_operand" "1"))) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 2) + (const_int 2))) + (set (match_operand:SI 1 "register_operand" "=S") + (plus:SI (match_dup 3) + (const_int 2))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "movsw" + [(set_attr "type" "str") + (set_attr "memory" "both") + (set_attr "mode" "HI")]) + +(define_insn "strmovhi_rex_1" + [(set (mem:HI (match_operand:DI 2 "register_operand" "0")) + (mem:HI (match_operand:DI 3 "register_operand" "1"))) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 2) + (const_int 2))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (match_dup 3) + (const_int 2))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "movsw" + [(set_attr "type" "str") + (set_attr "memory" "both") + (set_attr "mode" "HI")]) + +(define_insn "strmovqi_1" + [(set (mem:QI (match_operand:SI 2 "register_operand" "0")) + (mem:QI (match_operand:SI 3 "register_operand" "1"))) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 2) + (const_int 1))) + (set (match_operand:SI 1 "register_operand" "=S") + (plus:SI (match_dup 3) + (const_int 1))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "movsb" + [(set_attr "type" "str") + (set_attr "memory" "both") + (set_attr "mode" "QI")]) + +(define_insn "strmovqi_rex_1" + [(set (mem:QI (match_operand:DI 2 "register_operand" "0")) + (mem:QI (match_operand:DI 3 "register_operand" "1"))) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 2) + (const_int 1))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (match_dup 3) + (const_int 1))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "movsb" + [(set_attr "type" "str") + (set_attr "memory" "both") + (set_attr "mode" "QI")]) + +(define_insn "rep_movdi_rex64" + [(set (match_operand:DI 2 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (ashift:DI (match_operand:DI 5 "register_operand" "2") + (const_int 3)) + (match_operand:DI 3 "register_operand" "0"))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (ashift:DI (match_dup 5) (const_int 3)) + (match_operand:DI 4 "register_operand" "1"))) + (set (mem:BLK (match_dup 3)) + (mem:BLK (match_dup 4))) + (use (match_dup 5)) + (use (reg:SI 19))] + "TARGET_64BIT" + "{rep\;movsq|rep movsq}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "both") + (set_attr "mode" "DI")]) + +(define_insn "rep_movsi" + [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0)) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (ashift:SI (match_operand:SI 5 "register_operand" "2") + (const_int 2)) + (match_operand:SI 3 "register_operand" "0"))) + (set (match_operand:SI 1 "register_operand" "=S") + (plus:SI (ashift:SI (match_dup 5) (const_int 2)) + (match_operand:SI 4 "register_operand" "1"))) + (set (mem:BLK (match_dup 3)) + (mem:BLK (match_dup 4))) + (use (match_dup 5)) + (use (reg:SI 19))] + "!TARGET_64BIT" + "{rep\;movsl|rep movsd}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "both") + (set_attr "mode" "SI")]) + +(define_insn "rep_movsi_rex64" + [(set (match_operand:DI 2 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (ashift:DI (match_operand:DI 5 "register_operand" "2") + (const_int 2)) + (match_operand:DI 3 "register_operand" "0"))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (ashift:DI (match_dup 5) (const_int 2)) + (match_operand:DI 4 "register_operand" "1"))) + (set (mem:BLK (match_dup 3)) + (mem:BLK (match_dup 4))) + (use (match_dup 5)) + (use (reg:SI 19))] + "TARGET_64BIT" + "{rep\;movsl|rep movsd}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "both") + (set_attr "mode" "SI")]) + +(define_insn "rep_movqi" + [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0)) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_operand:SI 3 "register_operand" "0") + (match_operand:SI 5 "register_operand" "2"))) + (set (match_operand:SI 1 "register_operand" "=S") + (plus:SI (match_operand:SI 4 "register_operand" "1") (match_dup 5))) + (set (mem:BLK (match_dup 3)) + (mem:BLK (match_dup 4))) + (use (match_dup 5)) + (use (reg:SI 19))] + "!TARGET_64BIT" + "{rep\;movsb|rep movsb}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "both") + (set_attr "mode" "SI")]) + +(define_insn "rep_movqi_rex64" + [(set (match_operand:DI 2 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_operand:DI 3 "register_operand" "0") + (match_operand:DI 5 "register_operand" "2"))) + (set (match_operand:DI 1 "register_operand" "=S") + (plus:DI (match_operand:DI 4 "register_operand" "1") (match_dup 5))) + (set (mem:BLK (match_dup 3)) + (mem:BLK (match_dup 4))) + (use (match_dup 5)) + (use (reg:SI 19))] + "TARGET_64BIT" + "{rep\;movsb|rep movsb}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "both") + (set_attr "mode" "SI")]) -(define_expand "movsicc" +(define_expand "clrstrsi" + [(use (match_operand:BLK 0 "memory_operand" "")) + (use (match_operand:SI 1 "nonmemory_operand" "")) + (use (match_operand 2 "const_int_operand" ""))] + "" +{ + if (ix86_expand_clrstr (operands[0], operands[1], operands[2])) + DONE; + else + FAIL; +}) + +(define_expand "clrstrdi" + [(use (match_operand:BLK 0 "memory_operand" "")) + (use (match_operand:DI 1 "nonmemory_operand" "")) + (use (match_operand 2 "const_int_operand" ""))] + "TARGET_64BIT" +{ + if (ix86_expand_clrstr (operands[0], operands[1], operands[2])) + DONE; + else + FAIL; +}) + +;; Most CPUs don't like single string operations +;; Handle this case here to simplify previous expander. + +(define_expand "strsetdi_rex64" + [(set (mem:DI (match_operand:DI 0 "register_operand" "")) + (match_operand:DI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 8))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsetdi_rex_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsetsi" + [(set (mem:SI (match_operand:SI 0 "register_operand" "")) + (match_operand:SI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 4))) + (clobber (reg:CC 17))])] + "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_strsetsi_rex64 (operands[0], operands[1])); + DONE; + } + else if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsetsi_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsetsi_rex64" + [(set (mem:SI (match_operand:DI 0 "register_operand" "")) + (match_operand:SI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 4))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsetsi_rex_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsethi" + [(set (mem:HI (match_operand:SI 0 "register_operand" "")) + (match_operand:HI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 2))) + (clobber (reg:CC 17))])] + "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_strsethi_rex64 (operands[0], operands[1])); + DONE; + } + else if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsethi_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsethi_rex64" + [(set (mem:HI (match_operand:DI 0 "register_operand" "")) + (match_operand:HI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 2))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsethi_rex_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsetqi" + [(set (mem:QI (match_operand:SI 0 "register_operand" "")) + (match_operand:QI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))) + (clobber (reg:CC 17))])] + "" +{ + if (TARGET_64BIT) + { + emit_insn (gen_strsetqi_rex64 (operands[0], operands[1])); + DONE; + } + else if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsetqi_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_expand "strsetqi_rex64" + [(set (mem:QI (match_operand:DI 0 "register_operand" "")) + (match_operand:QI 1 "register_operand" "")) + (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 1))) + (clobber (reg:CC 17))])] + "TARGET_64BIT" +{ + if (TARGET_SINGLE_STRINGOP || optimize_size) + { + emit_insn (gen_strsetqi_rex_1 (operands[0], operands[0], operands[1])); + DONE; + } +}) + +(define_insn "strsetdi_rex_1" + [(set (mem:SI (match_operand:DI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "a")) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 1) + (const_int 8))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "stosq" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "DI")]) + +(define_insn "strsetsi_1" + [(set (mem:SI (match_operand:SI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "a")) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 1) + (const_int 4))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "{stosl|stosd}" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "SI")]) + +(define_insn "strsetsi_rex_1" + [(set (mem:SI (match_operand:DI 1 "register_operand" "0")) + (match_operand:SI 2 "register_operand" "a")) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 1) + (const_int 4))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "{stosl|stosd}" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "SI")]) + +(define_insn "strsethi_1" + [(set (mem:HI (match_operand:SI 1 "register_operand" "0")) + (match_operand:HI 2 "register_operand" "a")) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 1) + (const_int 2))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "stosw" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "HI")]) + +(define_insn "strsethi_rex_1" + [(set (mem:HI (match_operand:DI 1 "register_operand" "0")) + (match_operand:HI 2 "register_operand" "a")) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 1) + (const_int 2))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "stosw" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "HI")]) + +(define_insn "strsetqi_1" + [(set (mem:QI (match_operand:SI 1 "register_operand" "0")) + (match_operand:QI 2 "register_operand" "a")) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_dup 1) + (const_int 1))) + (use (reg:SI 19))] + "!TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "stosb" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "QI")]) + +(define_insn "strsetqi_rex_1" + [(set (mem:QI (match_operand:DI 1 "register_operand" "0")) + (match_operand:QI 2 "register_operand" "a")) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_dup 1) + (const_int 1))) + (use (reg:SI 19))] + "TARGET_64BIT && (TARGET_SINGLE_STRINGOP || optimize_size)" + "stosb" + [(set_attr "type" "str") + (set_attr "memory" "store") + (set_attr "mode" "QI")]) + +(define_insn "rep_stosdi_rex64" + [(set (match_operand:DI 1 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (ashift:DI (match_operand:DI 4 "register_operand" "1") + (const_int 3)) + (match_operand:DI 3 "register_operand" "0"))) + (set (mem:BLK (match_dup 3)) + (const_int 0)) + (use (match_operand:DI 2 "register_operand" "a")) + (use (match_dup 4)) + (use (reg:SI 19))] + "TARGET_64BIT" + "{rep\;stosq|rep stosq}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "store") + (set_attr "mode" "DI")]) + +(define_insn "rep_stossi" + [(set (match_operand:SI 1 "register_operand" "=c") (const_int 0)) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (ashift:SI (match_operand:SI 4 "register_operand" "1") + (const_int 2)) + (match_operand:SI 3 "register_operand" "0"))) + (set (mem:BLK (match_dup 3)) + (const_int 0)) + (use (match_operand:SI 2 "register_operand" "a")) + (use (match_dup 4)) + (use (reg:SI 19))] + "!TARGET_64BIT" + "{rep\;stosl|rep stosd}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "store") + (set_attr "mode" "SI")]) + +(define_insn "rep_stossi_rex64" + [(set (match_operand:DI 1 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (ashift:DI (match_operand:DI 4 "register_operand" "1") + (const_int 2)) + (match_operand:DI 3 "register_operand" "0"))) + (set (mem:BLK (match_dup 3)) + (const_int 0)) + (use (match_operand:SI 2 "register_operand" "a")) + (use (match_dup 4)) + (use (reg:SI 19))] + "TARGET_64BIT" + "{rep\;stosl|rep stosd}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "store") + (set_attr "mode" "SI")]) + +(define_insn "rep_stosqi" + [(set (match_operand:SI 1 "register_operand" "=c") (const_int 0)) + (set (match_operand:SI 0 "register_operand" "=D") + (plus:SI (match_operand:SI 3 "register_operand" "0") + (match_operand:SI 4 "register_operand" "1"))) + (set (mem:BLK (match_dup 3)) + (const_int 0)) + (use (match_operand:QI 2 "register_operand" "a")) + (use (match_dup 4)) + (use (reg:SI 19))] + "!TARGET_64BIT" + "{rep\;stosb|rep stosb}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "store") + (set_attr "mode" "QI")]) + +(define_insn "rep_stosqi_rex64" + [(set (match_operand:DI 1 "register_operand" "=c") (const_int 0)) + (set (match_operand:DI 0 "register_operand" "=D") + (plus:DI (match_operand:DI 3 "register_operand" "0") + (match_operand:DI 4 "register_operand" "1"))) + (set (mem:BLK (match_dup 3)) + (const_int 0)) + (use (match_operand:QI 2 "register_operand" "a")) + (use (match_dup 4)) + (use (reg:DI 19))] + "TARGET_64BIT" + "{rep\;stosb|rep stosb}" + [(set_attr "type" "str") + (set_attr "prefix_rep" "1") + (set_attr "memory" "store") + (set_attr "mode" "QI")]) + +(define_expand "cmpstrsi" [(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" - " + (compare:SI (match_operand:BLK 1 "general_operand" "") + (match_operand:BLK 2 "general_operand" ""))) + (use (match_operand 3 "general_operand" "")) + (use (match_operand 4 "immediate_operand" ""))] + "" { - if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) - FAIL; + rtx addr1, addr2, out, outlow, count, countreg, align; - operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), - GET_MODE (i386_compare_op0), - i386_compare_op0, i386_compare_op1); -}") + out = operands[0]; + if (GET_CODE (out) != REG) + out = gen_reg_rtx (SImode); -(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" - "#") + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0)); + + count = operands[3]; + countreg = ix86_zero_extend_to_Pmode (count); -(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" - "#") + /* %%% Iff we are testing strict equality, we can use known alignment + to good advantage. This may be possible with combine, particularly + once cc0 is dead. */ + align = operands[4]; -(define_split + emit_insn (gen_cld ()); + if (GET_CODE (count) == CONST_INT) + { + if (INTVAL (count) == 0) + { + emit_move_insn (operands[0], const0_rtx); + DONE; + } + if (TARGET_64BIT) + emit_insn (gen_cmpstrqi_nz_rex_1 (addr1, addr2, countreg, align, + addr1, addr2, countreg)); + else + emit_insn (gen_cmpstrqi_nz_1 (addr1, addr2, countreg, align, + addr1, addr2, countreg)); + } + else + { + if (TARGET_64BIT) + { + emit_insn (gen_cmpdi_1_rex64 (countreg, countreg)); + emit_insn (gen_cmpstrqi_rex_1 (addr1, addr2, countreg, align, + addr1, addr2, countreg)); + } + else + { + emit_insn (gen_cmpsi_1 (countreg, countreg)); + emit_insn (gen_cmpstrqi_1 (addr1, addr2, countreg, align, + addr1, addr2, countreg)); + } + } + + outlow = gen_lowpart (QImode, out); + emit_insn (gen_cmpintqi (outlow)); + emit_move_insn (out, gen_rtx_SIGN_EXTEND (SImode, outlow)); + + if (operands[0] != out) + emit_move_insn (operands[0], out); + + DONE; +}) + +;; Produce a tri-state integer (-1, 0, 1) from condition codes. + +(define_expand "cmpintqi" + [(set (match_dup 1) + (gtu:QI (reg:CC 17) (const_int 0))) + (set (match_dup 2) + (ltu:QI (reg:CC 17) (const_int 0))) + (parallel [(set (match_operand:QI 0 "register_operand" "") + (minus:QI (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "" + "operands[1] = gen_reg_rtx (QImode); + operands[2] = gen_reg_rtx (QImode);") + +;; 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. + +(define_insn "cmpstrqi_nz_1" + [(set (reg:CC 17) + (compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0")) + (mem:BLK (match_operand:SI 5 "register_operand" "1")))) + (use (match_operand:SI 6 "register_operand" "2")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (use (reg:SI 19)) + (clobber (match_operand:SI 0 "register_operand" "=S")) + (clobber (match_operand:SI 1 "register_operand" "=D")) + (clobber (match_operand:SI 2 "register_operand" "=c"))] + "!TARGET_64BIT" + "repz{\;| }cmpsb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +(define_insn "cmpstrqi_nz_rex_1" + [(set (reg:CC 17) + (compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0")) + (mem:BLK (match_operand:DI 5 "register_operand" "1")))) + (use (match_operand:DI 6 "register_operand" "2")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (use (reg:SI 19)) + (clobber (match_operand:DI 0 "register_operand" "=S")) + (clobber (match_operand:DI 1 "register_operand" "=D")) + (clobber (match_operand:DI 2 "register_operand" "=c"))] + "TARGET_64BIT" + "repz{\;| }cmpsb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +;; The same, but the count is not known to not be zero. + +(define_insn "cmpstrqi_1" + [(set (reg:CC 17) + (if_then_else:CC (ne (match_operand:SI 6 "register_operand" "2") + (const_int 0)) + (compare:CC (mem:BLK (match_operand:SI 4 "register_operand" "0")) + (mem:BLK (match_operand:SI 5 "register_operand" "1"))) + (const_int 0))) + (use (match_operand:SI 3 "immediate_operand" "i")) + (use (reg:CC 17)) + (use (reg:SI 19)) + (clobber (match_operand:SI 0 "register_operand" "=S")) + (clobber (match_operand:SI 1 "register_operand" "=D")) + (clobber (match_operand:SI 2 "register_operand" "=c"))] + "!TARGET_64BIT" + "repz{\;| }cmpsb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +(define_insn "cmpstrqi_rex_1" + [(set (reg:CC 17) + (if_then_else:CC (ne (match_operand:DI 6 "register_operand" "2") + (const_int 0)) + (compare:CC (mem:BLK (match_operand:DI 4 "register_operand" "0")) + (mem:BLK (match_operand:DI 5 "register_operand" "1"))) + (const_int 0))) + (use (match_operand:SI 3 "immediate_operand" "i")) + (use (reg:CC 17)) + (use (reg:SI 19)) + (clobber (match_operand:DI 0 "register_operand" "=S")) + (clobber (match_operand:DI 1 "register_operand" "=D")) + (clobber (match_operand:DI 2 "register_operand" "=c"))] + "TARGET_64BIT" + "repz{\;| }cmpsb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +(define_expand "strlensi" [(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)))] + (unspec:SI [(match_operand:BLK 1 "general_operand" "") + (match_operand:QI 2 "immediate_operand" "") + (match_operand 3 "immediate_operand" "")] 0))] + "" +{ + if (ix86_expand_strlen (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}) + +(define_expand "strlendi" + [(set (match_operand:DI 0 "register_operand" "") + (unspec:DI [(match_operand:BLK 1 "general_operand" "") + (match_operand:QI 2 "immediate_operand" "") + (match_operand 3 "immediate_operand" "")] 0))] + "" +{ + if (ix86_expand_strlen (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}) + +(define_insn "strlenqi_1" + [(set (match_operand:SI 0 "register_operand" "=&c") + (unspec:SI [(mem:BLK (match_operand:SI 5 "register_operand" "1")) + (match_operand:QI 2 "register_operand" "a") + (match_operand:SI 3 "immediate_operand" "i") + (match_operand:SI 4 "register_operand" "0")] 0)) + (use (reg:SI 19)) + (clobber (match_operand:SI 1 "register_operand" "=D")) + (clobber (reg:CC 17))] + "!TARGET_64BIT" + "repnz{\;| }scasb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +(define_insn "strlenqi_rex_1" + [(set (match_operand:DI 0 "register_operand" "=&c") + (unspec:DI [(mem:BLK (match_operand:DI 5 "register_operand" "1")) + (match_operand:QI 2 "register_operand" "a") + (match_operand:DI 3 "immediate_operand" "i") + (match_operand:DI 4 "register_operand" "0")] 0)) + (use (reg:SI 19)) + (clobber (match_operand:DI 1 "register_operand" "=D")) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "repnz{\;| }scasb" + [(set_attr "type" "str") + (set_attr "mode" "QI") + (set_attr "prefix_rep" "1")]) + +;; Peephole optimizations to clean up after cmpstr*. This should be +;; handled in combine, but it is not currently up to the task. +;; When used for their truth value, the cmpstr* expanders generate +;; code like this: +;; +;; repz cmpsb +;; seta %al +;; setb %dl +;; cmpb %al, %dl +;; jcc label +;; +;; The intermediate three instructions are unnecessary. + +;; This one handles cmpstr*_nz_1... +(define_peephole2 + [(parallel[ + (set (reg:CC 17) + (compare:CC (mem:BLK (match_operand 4 "register_operand" "")) + (mem:BLK (match_operand 5 "register_operand" "")))) + (use (match_operand 6 "register_operand" "")) + (use (match_operand:SI 3 "immediate_operand" "")) + (use (reg:SI 19)) + (clobber (match_operand 0 "register_operand" "")) + (clobber (match_operand 1 "register_operand" "")) + (clobber (match_operand 2 "register_operand" ""))]) + (set (match_operand:QI 7 "register_operand" "") + (gtu:QI (reg:CC 17) (const_int 0))) + (set (match_operand:QI 8 "register_operand" "") + (ltu:QI (reg:CC 17) (const_int 0))) + (set (reg 17) + (compare (match_dup 7) (match_dup 8))) + ] + "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])" + [(parallel[ + (set (reg:CC 17) + (compare:CC (mem:BLK (match_dup 4)) + (mem:BLK (match_dup 5)))) + (use (match_dup 6)) + (use (match_dup 3)) + (use (reg:SI 19)) + (clobber (match_dup 0)) + (clobber (match_dup 1)) + (clobber (match_dup 2))])] "") -(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)))] +;; ...and this one handles cmpstr*_1. +(define_peephole2 + [(parallel[ + (set (reg:CC 17) + (if_then_else:CC (ne (match_operand 6 "register_operand" "") + (const_int 0)) + (compare:CC (mem:BLK (match_operand 4 "register_operand" "")) + (mem:BLK (match_operand 5 "register_operand" ""))) + (const_int 0))) + (use (match_operand:SI 3 "immediate_operand" "")) + (use (reg:CC 17)) + (use (reg:SI 19)) + (clobber (match_operand 0 "register_operand" "")) + (clobber (match_operand 1 "register_operand" "")) + (clobber (match_operand 2 "register_operand" ""))]) + (set (match_operand:QI 7 "register_operand" "") + (gtu:QI (reg:CC 17) (const_int 0))) + (set (match_operand:QI 8 "register_operand" "") + (ltu:QI (reg:CC 17) (const_int 0))) + (set (reg 17) + (compare (match_dup 7) (match_dup 8))) + ] + "peep2_reg_dead_p (4, operands[7]) && peep2_reg_dead_p (4, operands[8])" + [(parallel[ + (set (reg:CC 17) + (if_then_else:CC (ne (match_dup 6) + (const_int 0)) + (compare:CC (mem:BLK (match_dup 4)) + (mem:BLK (match_dup 5))) + (const_int 0))) + (use (match_dup 3)) + (use (reg:CC 17)) + (use (reg:SI 19)) + (clobber (match_dup 0)) + (clobber (match_dup 1)) + (clobber (match_dup 2))])] "") -(define_insn "" + + +;; Conditional move instructions. + +(define_expand "movdicc" + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") + (match_operand:DI 2 "general_operand" "") + (match_operand:DI 3 "general_operand" "")))] + "TARGET_64BIT" + "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;") + +(define_insn "x86_movdicc_0_m1_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (if_then_else:DI (ltu (reg:CC 17) (const_int 0)) + (const_int -1) + (const_int 0))) + (clobber (reg:CC 17))] + "TARGET_64BIT" + "sbb{q}\t%0, %0" + ; Since we don't have the proper number of operands for an alu insn, + ; fill in all the blanks. + [(set_attr "type" "alu") + (set_attr "memory" "none") + (set_attr "imm_disp" "false") + (set_attr "mode" "DI") + (set_attr "length_immediate" "0")]) + +(define_insn "*movdicc_c_rex64" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (if_then_else:DI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:DI 2 "nonimmediate_operand" "rm,0") + (match_operand:DI 3 "nonimmediate_operand" "0,rm")))] + "TARGET_64BIT && TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + cmov%C1\t{%2, %0|%0, %2} + cmov%c1\t{%3, %0|%0, %3}" + [(set_attr "type" "icmov") + (set_attr "mode" "DI")]) + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "general_operand" "") + (match_operand:SI 3 "general_operand" "")))] + "" + "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;") + +;; Data flow gets confused by our desire for `sbbl reg,reg', and clearing +;; the register first winds up with `sbbl $0,reg', which is also weird. +;; So just document what we're doing explicitly. + +(define_insn "x86_movsicc_0_m1" + [(set (match_operand:SI 0 "register_operand" "=r") + (if_then_else:SI (ltu (reg:CC 17) (const_int 0)) + (const_int -1) + (const_int 0))) + (clobber (reg:CC 17))] + "" + "sbb{l}\t%0, %0" + ; Since we don't have the proper number of operands for an alu insn, + ; fill in all the blanks. + [(set_attr "type" "alu") + (set_attr "memory" "none") + (set_attr "imm_disp" "false") + (set_attr "mode" "SI") + (set_attr "length_immediate" "0")]) + +(define_insn "*movsicc_noc" [(set (match_operand:SI 0 "register_operand" "=r,r") - (if_then_else:SI (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) + (if_then_else:SI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (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);") + "TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + cmov%C1\t{%2, %0|%0, %2} + cmov%c1\t{%3, %0|%0, %3}" + [(set_attr "type" "icmov") + (set_attr "mode" "SI")]) (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" - "#") + "TARGET_CMOVE && TARGET_HIMODE_MATH" + "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;") -(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 "" +(define_insn "*movhicc_noc" [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) + (if_then_else:HI (match_operator 1 "ix86_comparison_operator" + [(reg 17) (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);") + "TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + cmov%C1\t{%2, %0|%0, %2} + cmov%c1\t{%3, %0|%0, %3}" + [(set_attr "type" "icmov") + (set_attr "mode" "HI")]) (define_expand "movsfcc" [(set (match_operand:SF 0 "register_operand" "") @@ -7752,425 +15823,830 @@ byte_xor_operation: (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. */ + "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") + +(define_insn "*movsfcc_1" + [(set (match_operand:SF 0 "register_operand" "=f,f,r,r") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:SF 2 "nonimmediate_operand" "f,0,rm,0") + (match_operand:SF 3 "nonimmediate_operand" "0,f,0,rm")))] + "TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + fcmov%F1\t{%2, %0|%0, %2} + fcmov%f1\t{%3, %0|%0, %3} + cmov%C1\t{%2, %0|%0, %2} + cmov%c1\t{%3, %0|%0, %3}" + [(set_attr "type" "fcmov,fcmov,icmov,icmov") + (set_attr "mode" "SF,SF,SI,SI")]) - 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); +(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" + "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") + +(define_insn "*movdfcc_1" + [(set (match_operand:DF 0 "register_operand" "=f,f,&r,&r") + (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0") + (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))] + "!TARGET_64BIT && TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + fcmov%F1\t{%2, %0|%0, %2} + fcmov%f1\t{%3, %0|%0, %3} + # + #" + [(set_attr "type" "fcmov,fcmov,multi,multi") + (set_attr "mode" "DF")]) + +(define_insn "*movdfcc_1_rex64" + [(set (match_operand:DF 0 "register_operand" "=f,f,&r,&r") + (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0") + (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))] + "TARGET_64BIT && TARGET_CMOVE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "@ + fcmov%F1\t{%2, %0|%0, %2} + fcmov%f1\t{%3, %0|%0, %3} + cmov%C1\t{%2, %0|%0, %2} + cmov%c1\t{%3, %0|%0, %3}" + [(set_attr "type" "fcmov,fcmov,icmov,icmov") + (set_attr "mode" "DF")]) - if (!temp) - FAIL; +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" + [(match_operand 4 "" "") (const_int 0)]) + (match_operand:DF 2 "nonimmediate_operand" "") + (match_operand:DF 3 "nonimmediate_operand" "")))] + "!TARGET_64BIT && !ANY_FP_REG_P (operands[0]) && reload_completed" + [(set (match_dup 2) + (if_then_else:SI (match_op_dup 1 [(match_dup 4) (const_int 0)]) + (match_dup 5) + (match_dup 7))) + (set (match_dup 3) + (if_then_else:SI (match_op_dup 1 [(match_dup 4) (const_int 0)]) + (match_dup 6) + (match_dup 8)))] + "split_di (operands+2, 1, operands+5, operands+6); + split_di (operands+3, 1, operands+7, operands+8); + split_di (operands, 1, operands+2, operands+3);") - operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); - break; +(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_64BIT && TARGET_CMOVE" + "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") + +(define_expand "movtfcc" + [(set (match_operand:TF 0 "register_operand" "") + (if_then_else:TF (match_operand 1 "comparison_operator" "") + (match_operand:TF 2 "register_operand" "") + (match_operand:TF 3 "register_operand" "")))] + "TARGET_CMOVE" + "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;") - 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 "*movxfcc_1" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (if_then_else:XF (match_operator 1 "fcmov_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:XF 2 "register_operand" "f,0") + (match_operand:XF 3 "register_operand" "0,f")))] + "!TARGET_64BIT && TARGET_CMOVE" + "@ + fcmov%F1\t{%2, %0|%0, %2} + fcmov%f1\t{%3, %0|%0, %3}" + [(set_attr "type" "fcmov") + (set_attr "mode" "XF")]) + +(define_insn "*movtfcc_1" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (if_then_else:TF (match_operator 1 "fcmov_comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand:TF 2 "register_operand" "f,0") + (match_operand:TF 3 "register_operand" "0,f")))] + "TARGET_CMOVE" + "@ + fcmov%F1\t{%2, %0|%0, %2} + fcmov%f1\t{%3, %0|%0, %3}" + [(set_attr "type" "fcmov") + (set_attr "mode" "XF")]) + +(define_expand "minsf3" + [(parallel [ + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE" + "") -(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 "*minsf" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x,f#x") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "0,0,f#x") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && TARGET_IEEE_FP" "#") -(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_insn "*minsf_nonieee" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "%0,0") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && !TARGET_IEEE_FP" "#") (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)))] - "") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:SF (lt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) + +;; We can't represent the LT test directly. Do this by swapping the operands. (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))) + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "register_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "FP_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 2) + (match_dup 1))) (set (match_dup 0) - (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)]) - (match_dup 4) (match_dup 5)))] - "") + (if_then_else:SF (ge (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*minsf_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (lt (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE && reload_completed" + "minss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_expand "mindf3" + [(parallel [ + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE2 && TARGET_SSE_MATH" + "#") -(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_insn "*mindf" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y,f#Y") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "0,0,f#Y") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_IEEE_FP && TARGET_SSE_MATH" + "#") -(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; +(define_insn "*mindf_nonieee" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_IEEE_FP" + "#") - if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) - FAIL; +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:DF (lt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) - /* The floating point conditional move instructions don't directly - support conditions resulting from a signed integer comparison. */ +;; We can't represent the LT test directly. Do this by swapping the operands. +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "register_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "FP_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 2) + (match_dup 2))) + (set (match_dup 0) + (if_then_else:DF (ge (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*mindf_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (if_then_else:DF (lt (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE2 && TARGET_SSE_MATH && reload_completed" + "minsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) + +(define_expand "maxsf3" + [(parallel [ + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE" + "#") - 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); +(define_insn "*maxsf" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x,f#x") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "0,0,f#x") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && TARGET_IEEE_FP" + "#") - if (!temp) - FAIL; +(define_insn "*maxsf_nonieee" + [(set (match_operand:SF 0 "register_operand" "=x#f,f#x") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "%0,0") + (match_operand:SF 2 "nonimmediate_operand" "xm#f,f#x")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE && !TARGET_IEEE_FP" + "#") - operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); - break; +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "nonimmediate_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:SF (gt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) - default: - operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), - GET_MODE (i386_compare_op0), - i386_compare_op0, i386_compare_op1); - break; - } -}") +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "") + (match_operand:SF 2 "register_operand" "")) + (match_operand:SF 3 "register_operand" "") + (match_operand:SF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "FP_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (if_then_else:SF (gt (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*maxsf_sse" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (gt (match_operand:SF 1 "register_operand" "0") + (match_operand:SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE && reload_completed" + "maxss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "SF")]) + +(define_expand "maxdf3" + [(parallel [ + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))])] + "TARGET_SSE2 && TARGET_SSE_MATH" + "#") -(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 "*maxdf" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y,f#Y") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "0,0,f#Y") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y,0")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_IEEE_FP" "#") -(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_insn "*maxdf_nonieee" + [(set (match_operand:DF 0 "register_operand" "=Y#f,f#Y") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "%0,0") + (match_operand:DF 2 "nonimmediate_operand" "Ym#f,f#Y")) + (match_dup 1) + (match_dup 2))) + (clobber (reg:CC 17))] + "TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_IEEE_FP" "#") (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)))] - "") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "nonimmediate_operand" ""))) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (match_dup 0) + (if_then_else:DF (gt (match_dup 1) + (match_dup 2)) + (match_dup 1) + (match_dup 2)))]) (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))) + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "register_operand" "")) + (match_operand:DF 3 "register_operand" "") + (match_operand:DF 4 "register_operand" ""))) + (clobber (reg:CC 17))] + "FP_REG_P (operands[0]) && reload_completed + && ((operands_match_p (operands[1], operands[3]) + && operands_match_p (operands[2], operands[4])) + || (operands_match_p (operands[1], operands[4]) + && operands_match_p (operands[2], operands[3])))" + [(set (reg:CCFP 17) + (compare:CCFP (match_dup 1) + (match_dup 2))) (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);") + (if_then_else:DF (gt (reg:CCFP 17) (const_int 0)) + (match_dup 1) + (match_dup 2)))]) + +(define_insn "*maxdf_sse" + [(set (match_operand:DF 0 "register_operand" "=Y") + (if_then_else:DF (gt (match_operand:DF 1 "register_operand" "0") + (match_operand:DF 2 "nonimmediate_operand" "Ym")) + (match_dup 1) + (match_dup 2)))] + "TARGET_SSE2 && TARGET_SSE_MATH && reload_completed" + "maxsd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse") + (set_attr "mode" "DF")]) + +;; Misc patterns (?) -(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" - " +;; This pattern exists to put a dependency on all ebp-based memory accesses. +;; Otherwise there will be nothing to keep +;; +;; [(set (reg ebp) (reg esp))] +;; [(set (reg esp) (plus (reg esp) (const_int -160000))) +;; (clobber (eflags)] +;; [(set (mem (plus (reg ebp) (const_int -160000))) (const_int 0))] +;; +;; in proper program order. +(define_expand "pro_epilogue_adjust_stack" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (match_operand:SI 1 "register_operand" "0,r") + (match_operand:SI 2 "immediate_operand" "i,i"))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "" { - rtx temp; + if (TARGET_64BIT) + { + emit_insn (gen_pro_epilogue_adjust_stack_rex64 + (operands[0], operands[1], operands[2])); + DONE; + } +}) - if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) - FAIL; +(define_insn "*pro_epilogue_adjust_stack_1" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (match_operand:SI 1 "register_operand" "0,r") + (match_operand:SI 2 "immediate_operand" "i,i"))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))] + "!TARGET_64BIT" +{ + switch (get_attr_type (insn)) + { + case TYPE_IMOV: + return "mov{l}\t{%1, %0|%0, %1}"; + + case TYPE_ALU: + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{l}\t{%2, %0|%0, %2}"; + } + return "add{l}\t{%2, %0|%0, %2}"; - /* The floating point conditional move instructions don't directly - support conditions resulting from a signed integer comparison. */ + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{l}\t{%a2, %0|%0, %a2}"; - switch (GET_CODE (operands[1])) + default: + abort (); + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "0") + (const_string "alu") + (match_operand:SI 2 "const0_operand" "") + (const_string "imov") + ] + (const_string "lea"))) + (set_attr "mode" "SI")]) + +(define_insn "pro_epilogue_adjust_stack_rex64" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "register_operand" "0,r") + (match_operand:DI 2 "x86_64_immediate_operand" "e,e"))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))] + "TARGET_64BIT" +{ + switch (get_attr_type (insn)) { - 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; + case TYPE_IMOV: + return "mov{q}\t{%1, %0|%0, %1}"; + + case TYPE_ALU: + if (GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{q}\t{%2, %0|%0, %2}"; + } + return "add{q}\t{%2, %0|%0, %2}"; - operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); - break; + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{q}\t{%a2, %0|%0, %a2}"; default: - operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), - GET_MODE (i386_compare_op0), - i386_compare_op0, i386_compare_op1); - break; + abort (); } -}") +} + [(set (attr "type") + (cond [(eq_attr "alternative" "0") + (const_string "alu") + (match_operand:DI 2 "const0_operand" "") + (const_string "imov") + ] + (const_string "lea"))) + (set_attr "mode" "DI")]) + + +;; Placeholder for the conditional moves. This one is split either to SSE +;; based moves emulation or to usual cmove sequence. Little bit unfortunate +;; fact is that compares supported by the cmp??ss instructions are exactly +;; swapped of those supported by cmove sequence. +;; The EQ/NE comparisons also needs bit care, since they are not directly +;; supported by i387 comparisons and we do need to emit two conditional moves +;; in tandem. + +(define_insn "sse_movsfcc" + [(set (match_operand:SF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?f#xr,?f#xr,?r#xf,?r#xf,?r#xf,?r#xf") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "0#fx,x#fx,f#x,f#x,xm#f,xm#f,f#x,f#x,xm#f,xm#f") + (match_operand:SF 5 "nonimmediate_operand" "xm#f,xm#f,f#x,f#x,x#f,x#f,f#x,f#x,x#f,x#f")]) + (match_operand:SF 2 "nonimmediate_operand" "x#fr,0#fr,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx,0#rx") + (match_operand:SF 3 "nonimmediate_operand" "x#fr,x#fr,0#fx,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx"))) + (clobber (match_scratch:SF 6 "=2,&4,X,X,X,X,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM) + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE))" + "#") -(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 "sse_movsfcc_eq" + [(set (match_operand:SF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?r#xf,?r#xf") + (if_then_else:SF (eq (match_operand:SF 3 "nonimmediate_operand" "%0#fx,x#fx,f#x,xm#f,f#x,xm#f") + (match_operand:SF 4 "nonimmediate_operand" "xm#f,xm#f,f#x,x#f,f#x,x#f")) + (match_operand:SF 1 "nonimmediate_operand" "x#fr,0#fr,0#fx,0#fx,0#rx,0#rx") + (match_operand:SF 2 "nonimmediate_operand" "x#fr,x#fr,f#fx,f#fx,rm#rx,rm#rx"))) + (clobber (match_scratch:SF 5 "=1,&3,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" "#") -(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_insn "sse_movdfcc" + [(set (match_operand:DF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?f#xr,?f#xr,?r#xf,?r#xf,?r#xf,?r#xf") + (if_then_else:DF (match_operator 1 "sse_comparison_operator" + [(match_operand:DF 4 "nonimmediate_operand" "0#fx,x#fx,f#x,f#x,xm#f,xm#f,f#x,f#x,xm#f,xm#f") + (match_operand:DF 5 "nonimmediate_operand" "xm#f,xm#f,f#x,f#x,x#f,x#f,f#x,f#x,x#f,x#f")]) + (match_operand:DF 2 "nonimmediate_operand" "x#fr,0#fr,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx,0#rx") + (match_operand:DF 3 "nonimmediate_operand" "x#fr,x#fr,0#fx,f#fx,0#fx,f#fx,0#fx,rm#rx,0#rx,rm#rx"))) + (clobber (match_scratch:DF 6 "=2,&4,X,X,X,X,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE2 + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM) + && (!TARGET_IEEE_FP + || (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE))" "#") -(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_insn "sse_movdfcc_eq" + [(set (match_operand:DF 0 "register_operand" "=&x#rf,x#rf,?f#xr,?f#xr,?r#xf,?r#xf") + (if_then_else:DF (eq (match_operand:DF 3 "nonimmediate_operand" "%0#fx,x#fx,f#x,xm#f,f#x,xm#f") + (match_operand:DF 4 "nonimmediate_operand" "xm#f,xm#f,f#x,x#f,f#x,x#f")) + (match_operand:DF 1 "nonimmediate_operand" "x#fr,0#fr,0#fx,0#fx,0#rx,0#rx") + (match_operand:DF 2 "nonimmediate_operand" "x#fr,x#fr,f#fx,f#fx,rm#rx,rm#rx"))) + (clobber (match_scratch:DF 5 "=1,&3,X,X,X,X")) + (clobber (reg:CC 17))] + "TARGET_SSE + && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)" + "#") +;; For non-sse moves just expand the usual cmove sequence. (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)))] - "") + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 4 "nonimmediate_operand" "") + (match_operand 5 "register_operand" "")]) + (match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "nonimmediate_operand" ""))) + (clobber (match_operand 6 "" "")) + (clobber (reg:CC 17))] + "!SSE_REG_P (operands[0]) && reload_completed + && VALID_SSE_REG_MODE (GET_MODE (operands[0]))" + [(const_int 0)] +{ + ix86_compare_op0 = operands[5]; + ix86_compare_op1 = operands[4]; + operands[1] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])), + VOIDmode, operands[5], operands[4]); + ix86_expand_fp_movcc (operands); + DONE; +}) + +;; Split SSE based conditional move into seqence: +;; cmpCC op0, op4 - set op0 to 0 or ffffffff depending on the comparison +;; and op2, op0 - zero op2 if comparison was false +;; nand op0, op3 - load op3 to op0 if comparison was false +;; or op2, op0 - get the non-zero one into the result. +(define_split + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "sse_comparison_operator" + [(match_operand 4 "register_operand" "") + (match_operand 5 "nonimmediate_operand" "")]) + (match_operand 2 "register_operand" "") + (match_operand 3 "register_operand" ""))) + (clobber (match_operand 6 "" "")) + (clobber (reg:CC 17))] + "SSE_REG_P (operands[0]) && reload_completed" + [(set (match_dup 4) (match_op_dup 1 [(match_dup 4) (match_dup 5)])) + (set (subreg:TI (match_dup 2) 0) (and:TI (subreg:TI (match_dup 2) 0) + (subreg:TI (match_dup 4) 0))) + (set (subreg:TI (match_dup 4) 0) (and:TI (not:TI (subreg:TI (match_dup 4) 0)) + (subreg:TI (match_dup 3) 0))) + (set (subreg:TI (match_dup 0) 0) (ior:TI (subreg:TI (match_dup 6) 0) + (subreg:TI (match_dup 7) 0)))] +{ + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (operands_match_p (operands[0], operands[4])) + operands[6] = operands[4], operands[7] = operands[2]; + else + operands[6] = operands[2], operands[7] = operands[4]; +}) + +;; Special case of conditional move we can handle effectivly. +;; Do not brother with the integer/floating point case, since these are +;; bot considerably slower, unlike in the generic case. +(define_insn "*sse_movsfcc_const0_1" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE" + "#") -(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_insn "*sse_movsfcc_const0_2" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE" + "#") -(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; +(define_insn "*sse_movsfcc_const0_3" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE" + "#") - operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), - GET_MODE (i386_compare_op0), - i386_compare_op0, i386_compare_op1); -}") +(define_insn "*sse_movsfcc_const0_4" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE" + "#") -(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 "*sse_movdfcc_const0_1" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE2" "#") -(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_insn "*sse_movdfcc_const0_2" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "sse_comparison_operator" + [(match_operand:SF 4 "register_operand" "0") + (match_operand:SF 5 "nonimmediate_operand" "xm")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE2" "#") -(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_insn "*sse_movdfcc_const0_3" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "register_operand" "x") + (match_operand:SF 3 "const0_operand" "X")))] + "TARGET_SSE2" + "#") + +(define_insn "*sse_movdfcc_const0_4" + [(set (match_operand:SF 0 "register_operand" "=x") + (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" + [(match_operand:SF 4 "nonimmediate_operand" "xm") + (match_operand:SF 5 "register_operand" "0")]) + (match_operand:SF 2 "const0_operand" "X") + (match_operand:SF 3 "register_operand" "x")))] + "TARGET_SSE2" + "#") (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" + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand 4 "register_operand" "") + (match_operand 5 "nonimmediate_operand" "")]) + (match_operand 2 "nonmemory_operand" "") + (match_operand 3 "nonmemory_operand" "")))] + "SSE_REG_P (operands[0]) && reload_completed + && (const0_operand (operands[2], GET_MODE (operands[0])) + || const0_operand (operands[3], GET_MODE (operands[0])))" + [(set (match_dup 0) (match_op_dup 1 [(match_dup 0) (match_dup 5)])) + (set (subreg:TI (match_dup 0) 0) (and:TI (match_dup 6) + (subreg:TI (match_dup 7) 0)))] +{ + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (!sse_comparison_operator (operands[1], VOIDmode)) + { + rtx tmp = operands[5]; + operands[5] = operands[4]; + operands[4] = tmp; + PUT_CODE (operands[1], swap_condition (GET_CODE (operands[1]))); + } + if (const0_operand (operands[2], GET_MODE (operands[0]))) + { + operands[7] = operands[3]; + operands[6] = gen_rtx_NOT (TImode, gen_rtx_SUBREG (TImode, operands[0], + 0)); + } + else + { + operands[7] = operands[2]; + operands[6] = gen_rtx_SUBREG (TImode, operands[0], 0); + } +}) + +(define_expand "allocate_stack_worker" + [(match_operand:SI 0 "register_operand" "")] + "TARGET_STACK_PROBE" +{ + if (TARGET_64BIT) + emit_insn (gen_allocate_stack_worker_rex64 (operands[0])); + else + emit_insn (gen_allocate_stack_worker_1 (operands[0])); + DONE; +}) + +(define_insn "allocate_stack_worker_1" [(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")]) + (clobber (match_dup 0)) + (clobber (reg:CC 17))] + "!TARGET_64BIT && TARGET_STACK_PROBE" + "call\t__alloca" + [(set_attr "type" "multi") + (set_attr "length" "5")]) + +(define_insn "allocate_stack_worker_rex64" + [(unspec:DI [(match_operand:DI 0 "register_operand" "a")] 3) + (set (reg:DI 7) (minus:DI (reg:DI 7) (match_dup 0))) + (clobber (match_dup 0)) + (clobber (reg:CC 17))] + "TARGET_64BIT && TARGET_STACK_PROBE" + "call\t__alloca" + [(set_attr "type" "multi") + (set_attr "length" "5")]) (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" - " + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (reg:SI 7) + (match_operand:SI 1 "general_operand" ""))) + (clobber (reg:CC 17))]) + (parallel [(set (reg:SI 7) + (minus:SI (reg:SI 7) (match_dup 1))) + (clobber (reg:CC 17))])] + "TARGET_STACK_PROBE" { #ifdef CHECK_STACK_LIMIT if (GET_CODE (operands[1]) == CONST_INT @@ -8184,22 +16660,2996 @@ byte_xor_operation: emit_move_insn (operands[0], virtual_stack_dynamic_rtx); DONE; -}") +}) -(define_expand "exception_receiver" - [(const_int 0)] - "flag_pic" - " +(define_expand "builtin_setjmp_receiver" + [(label_ref (match_operand 0 "" ""))] + "!TARGET_64BIT && flag_pic" { - load_pic_register (1); + load_pic_register (); DONE; -}") +}) + +;; Avoid redundant prefixes by splitting HImode arithmetic to SImode. -(define_expand "builtin_setjmp_receiver" - [(label_ref (match_operand 0 "" ""))] - "flag_pic" - " +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operator 3 "promotable_binary_operator" + [(match_operand 1 "register_operand" "") + (match_operand 2 "aligned_operand" "")])) + (clobber (reg:CC 17))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + && ((GET_MODE (operands[0]) == HImode + && (!optimize_size || GET_CODE (operands[2]) != CONST_INT + || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))) + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(parallel [(set (match_dup 0) + (match_op_dup 3 [(match_dup 1) (match_dup 2)])) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + if (GET_CODE (operands[3]) != ASHIFT) + operands[2] = gen_lowpart (SImode, operands[2]); + PUT_MODE (operands[3], SImode);") + +(define_split + [(set (reg 17) + (compare (and (match_operand 1 "aligned_operand" "") + (match_operand 2 "const_int_operand" "")) + (const_int 0))) + (set (match_operand 0 "register_operand" "") + (and (match_dup 1) (match_dup 2)))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + && ix86_match_ccmode (insn, CCNOmode) + && (GET_MODE (operands[0]) == HImode + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO (and:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (and:SI (match_dup 1) (match_dup 2)))])] + "operands[2] + = GEN_INT (trunc_int_for_mode (INTVAL (operands[2]) + & GET_MODE_MASK (GET_MODE (operands[0])), + SImode)); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]);") + +(define_split + [(set (reg 17) + (compare (and (match_operand 0 "aligned_operand" "") + (match_operand 1 "const_int_operand" "")) + (const_int 0)))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + && ix86_match_ccmode (insn, CCNOmode) + && (GET_MODE (operands[0]) == HImode + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(set (reg:CCNO 17) + (compare:CCNO (and:SI (match_dup 0) (match_dup 1)) + (const_int 0)))] + "operands[1] + = GEN_INT (trunc_int_for_mode (INTVAL (operands[1]) + & GET_MODE_MASK (GET_MODE (operands[0])), + SImode)); + operands[0] = gen_lowpart (SImode, operands[0]);") + +(define_split + [(set (match_operand 0 "register_operand" "") + (neg (match_operand 1 "register_operand" ""))) + (clobber (reg:CC 17))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + && (GET_MODE (operands[0]) == HImode + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(parallel [(set (match_dup 0) + (neg:SI (match_dup 1))) + (clobber (reg:CC 17))])] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]);") + +(define_split + [(set (match_operand 0 "register_operand" "") + (not (match_operand 1 "register_operand" "")))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + && (GET_MODE (operands[0]) == HImode + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(set (match_dup 0) + (not:SI (match_dup 1)))] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]);") + +(define_split + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand 2 "register_operand" "") + (match_operand 3 "register_operand" "")))] + "! TARGET_PARTIAL_REG_STALL && TARGET_CMOVE + && (GET_MODE (operands[0]) == HImode + || (GET_MODE (operands[0]) == QImode + && (TARGET_PROMOTE_QImode || optimize_size)))" + [(set (match_dup 0) + (if_then_else:SI (match_dup 1) (match_dup 2) (match_dup 3)))] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[2] = gen_lowpart (SImode, operands[2]); + operands[3] = gen_lowpart (SImode, operands[3]);") + + +;; RTL Peephole optimizations, run before sched2. These primarily look to +;; transform a complex memory operation into two memory to register operations. + +;; Don't push memory operands +(define_peephole2 + [(set (match_operand:SI 0 "push_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (match_scratch:SI 2 "r")] + "! optimize_size && ! TARGET_PUSH_MEMORY" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "memory_operand" "")) + (match_scratch:DI 2 "r")] + "! optimize_size && ! TARGET_PUSH_MEMORY" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +;; We need to handle SFmode only, because DFmode and XFmode is split to +;; SImode pushes. +(define_peephole2 + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "memory_operand" "")) + (match_scratch:SF 2 "r")] + "! optimize_size && ! TARGET_PUSH_MEMORY" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(set (match_operand:HI 0 "push_operand" "") + (match_operand:HI 1 "memory_operand" "")) + (match_scratch:HI 2 "r")] + "! optimize_size && ! TARGET_PUSH_MEMORY" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(set (match_operand:QI 0 "push_operand" "") + (match_operand:QI 1 "memory_operand" "")) + (match_scratch:QI 2 "q")] + "! optimize_size && ! TARGET_PUSH_MEMORY" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +;; Don't move an immediate directly to memory when the instruction +;; gets too big. +(define_peephole2 + [(match_scratch:SI 1 "r") + (set (match_operand:SI 0 "memory_operand" "") + (const_int 0))] + "! optimize_size + && ! TARGET_USE_MOV0 + && TARGET_SPLIT_LONG_MOVES + && get_attr_length (insn) >= ix86_cost->large_insn + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 1) (const_int 0)) + (clobber (reg:CC 17))]) + (set (match_dup 0) (match_dup 1))] + "") + +(define_peephole2 + [(match_scratch:HI 1 "r") + (set (match_operand:HI 0 "memory_operand" "") + (const_int 0))] + "! optimize_size + && ! TARGET_USE_MOV0 + && TARGET_SPLIT_LONG_MOVES + && get_attr_length (insn) >= ix86_cost->large_insn + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 2) (const_int 0)) + (clobber (reg:CC 17))]) + (set (match_dup 0) (match_dup 1))] + "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));") + +(define_peephole2 + [(match_scratch:QI 1 "q") + (set (match_operand:QI 0 "memory_operand" "") + (const_int 0))] + "! optimize_size + && ! TARGET_USE_MOV0 + && TARGET_SPLIT_LONG_MOVES + && get_attr_length (insn) >= ix86_cost->large_insn + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 2) (const_int 0)) + (clobber (reg:CC 17))]) + (set (match_dup 0) (match_dup 1))] + "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));") + +(define_peephole2 + [(match_scratch:SI 2 "r") + (set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "immediate_operand" ""))] + "! optimize_size + && get_attr_length (insn) >= ix86_cost->large_insn + && TARGET_SPLIT_LONG_MOVES" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(match_scratch:HI 2 "r") + (set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "immediate_operand" ""))] + "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn + && TARGET_SPLIT_LONG_MOVES" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(match_scratch:QI 2 "q") + (set (match_operand:QI 0 "memory_operand" "") + (match_operand:QI 1 "immediate_operand" ""))] + "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn + && TARGET_SPLIT_LONG_MOVES" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +;; Don't compare memory with zero, load and use a test instead. +(define_peephole2 + [(set (reg 17) + (compare (match_operand:SI 0 "memory_operand" "") + (const_int 0))) + (match_scratch:SI 3 "r")] + "ix86_match_ccmode (insn, CCNOmode) && ! optimize_size" + [(set (match_dup 3) (match_dup 0)) + (set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))] + "") + +;; NOT is not pairable on Pentium, while XOR is, but one byte longer. +;; Don't split NOTs with a displacement operand, because resulting XOR +;; will not be pariable anyway. +;; +;; On AMD K6, NOT is vector decoded with memory operand that can not be +;; represented using a modRM byte. The XOR replacement is long decoded, +;; so this split helps here as well. +;; +;; Note: Can't do this as a regular split because we can't get proper +;; lifetime information then. + +(define_peephole2 + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "")))] + "!optimize_size + && peep2_regno_dead_p (0, FLAGS_REG) + && ((TARGET_PENTIUM + && (GET_CODE (operands[0]) != MEM + || !memory_displacement_operand (operands[0], SImode))) + || (TARGET_K6 && long_memory_operand (operands[0], SImode)))" + [(parallel [(set (match_dup 0) + (xor:SI (match_dup 1) (const_int -1))) + (clobber (reg:CC 17))])] + "") + +(define_peephole2 + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (not:HI (match_operand:HI 1 "nonimmediate_operand" "")))] + "!optimize_size + && peep2_regno_dead_p (0, FLAGS_REG) + && ((TARGET_PENTIUM + && (GET_CODE (operands[0]) != MEM + || !memory_displacement_operand (operands[0], HImode))) + || (TARGET_K6 && long_memory_operand (operands[0], HImode)))" + [(parallel [(set (match_dup 0) + (xor:HI (match_dup 1) (const_int -1))) + (clobber (reg:CC 17))])] + "") + +(define_peephole2 + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "")))] + "!optimize_size + && peep2_regno_dead_p (0, FLAGS_REG) + && ((TARGET_PENTIUM + && (GET_CODE (operands[0]) != MEM + || !memory_displacement_operand (operands[0], QImode))) + || (TARGET_K6 && long_memory_operand (operands[0], QImode)))" + [(parallel [(set (match_dup 0) + (xor:QI (match_dup 1) (const_int -1))) + (clobber (reg:CC 17))])] + "") + +;; Non pairable "test imm, reg" instructions can be translated to +;; "and imm, reg" if reg dies. The "and" form is also shorter (one +;; byte opcode instead of two, have a short form for byte operands), +;; so do it for other CPUs as well. Given that the value was dead, +;; this should not create any new dependencies. Pass on the sub-word +;; versions if we're concerned about partial register stalls. + +(define_peephole2 + [(set (reg 17) + (compare (and:SI (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "immediate_operand" "")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode) + && (true_regnum (operands[0]) != 0 + || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K')) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel + [(set (reg:CCNO 17) + (compare:CCNO (and:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (and:SI (match_dup 0) (match_dup 1)))])] + "") + +;; We don't need to handle HImode case, because it will be promoted to SImode +;; on ! TARGET_PARTIAL_REG_STALL + +(define_peephole2 + [(set (reg 17) + (compare (and:QI (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "immediate_operand" "")) + (const_int 0)))] + "! TARGET_PARTIAL_REG_STALL + && ix86_match_ccmode (insn, CCNOmode) + && true_regnum (operands[0]) != 0 + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel + [(set (reg:CCNO 17) + (compare:CCNO (and:QI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (and:QI (match_dup 0) (match_dup 1)))])] + "") + +(define_peephole2 + [(set (reg 17) + (compare + (and:SI + (zero_extract:SI + (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (match_operand 1 "const_int_operand" "")) + (const_int 0)))] + "! TARGET_PARTIAL_REG_STALL + && ix86_match_ccmode (insn, CCNOmode) + && true_regnum (operands[0]) != 0 + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCNO 17) + (compare:CCNO + (and:SI + (zero_extract:SI + (match_dup 0) + (const_int 8) + (const_int 8)) + (match_dup 1)) + (const_int 0))) + (set (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI + (match_dup 0) + (const_int 8) + (const_int 8)) + (match_dup 1)))])] + "") + +;; Don't do logical operations with memory inputs. +(define_peephole2 + [(match_scratch:SI 2 "r") + (parallel [(set (match_operand:SI 0 "register_operand" "") + (match_operator:SI 3 "arith_or_logical_operator" + [(match_dup 0) + (match_operand:SI 1 "memory_operand" "")])) + (clobber (reg:CC 17))])] + "! optimize_size && ! TARGET_READ_MODIFY" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 0) + (match_op_dup 3 [(match_dup 0) (match_dup 2)])) + (clobber (reg:CC 17))])] + "") + +(define_peephole2 + [(match_scratch:SI 2 "r") + (parallel [(set (match_operand:SI 0 "register_operand" "") + (match_operator:SI 3 "arith_or_logical_operator" + [(match_operand:SI 1 "memory_operand" "") + (match_dup 0)])) + (clobber (reg:CC 17))])] + "! optimize_size && ! TARGET_READ_MODIFY" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 0) + (match_op_dup 3 [(match_dup 2) (match_dup 0)])) + (clobber (reg:CC 17))])] + "") + +; Don't do logical operations with memory outputs +; +; These two don't make sense for PPro/PII -- we're expanding a 4-uop +; instruction into two 1-uop insns plus a 2-uop insn. That last has +; the same decoder scheduling characteristics as the original. + +(define_peephole2 + [(match_scratch:SI 2 "r") + (parallel [(set (match_operand:SI 0 "memory_operand" "") + (match_operator:SI 3 "arith_or_logical_operator" + [(match_dup 0) + (match_operand:SI 1 "nonmemory_operand" "")])) + (clobber (reg:CC 17))])] + "! optimize_size && ! TARGET_READ_MODIFY_WRITE" + [(set (match_dup 2) (match_dup 0)) + (parallel [(set (match_dup 2) + (match_op_dup 3 [(match_dup 2) (match_dup 1)])) + (clobber (reg:CC 17))]) + (set (match_dup 0) (match_dup 2))] + "") + +(define_peephole2 + [(match_scratch:SI 2 "r") + (parallel [(set (match_operand:SI 0 "memory_operand" "") + (match_operator:SI 3 "arith_or_logical_operator" + [(match_operand:SI 1 "nonmemory_operand" "") + (match_dup 0)])) + (clobber (reg:CC 17))])] + "! optimize_size && ! TARGET_READ_MODIFY_WRITE" + [(set (match_dup 2) (match_dup 0)) + (parallel [(set (match_dup 2) + (match_op_dup 3 [(match_dup 1) (match_dup 2)])) + (clobber (reg:CC 17))]) + (set (match_dup 0) (match_dup 2))] + "") + +;; Attempt to always use XOR for zeroing registers. +(define_peephole2 + [(set (match_operand 0 "register_operand" "") + (const_int 0))] + "(GET_MODE (operands[0]) == QImode + || GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == SImode + || (GET_MODE (operands[0]) == DImode && TARGET_64BIT)) + && (! TARGET_USE_MOV0 || optimize_size) + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (const_int 0)) + (clobber (reg:CC 17))])] + "operands[0] = gen_rtx_REG (GET_MODE (operands[0]) == DImode ? DImode : SImode, + true_regnum (operands[0]));") + +(define_peephole2 + [(set (strict_low_part (match_operand 0 "register_operand" "")) + (const_int 0))] + "(GET_MODE (operands[0]) == QImode + || GET_MODE (operands[0]) == HImode) + && (! TARGET_USE_MOV0 || optimize_size) + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (strict_low_part (match_dup 0)) (const_int 0)) + (clobber (reg:CC 17))])]) + +;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg. +(define_peephole2 + [(set (match_operand 0 "register_operand" "") + (const_int -1))] + "(GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == SImode + || (GET_MODE (operands[0]) == DImode && TARGET_64BIT)) + && (optimize_size || TARGET_PENTIUM) + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (const_int -1)) + (clobber (reg:CC 17))])] + "operands[0] = gen_rtx_REG (GET_MODE (operands[0]) == DImode ? DImode : SImode, + true_regnum (operands[0]));") + +;; Attempt to convert simple leas to adds. These can be created by +;; move expanders. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "nonmemory_operand" "")))] + "peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (subreg:SI (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "nonmemory_operand" "")) 0))] + "peep2_regno_dead_p (0, FLAGS_REG) && REGNO (operands[0]) == REGNO (operands[1])" + [(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[2] = gen_lowpart (SImode, operands[2]);") + +(define_peephole2 + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_dup 0) + (match_operand:DI 1 "x86_64_general_operand" "")))] + "peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (plus:DI (match_dup 0) (match_dup 1))) + (clobber (reg:CC 17))])] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (mult:SI (match_dup 0) + (match_operand:SI 1 "const_int_operand" "")))] + "exact_log2 (INTVAL (operands[1])) >= 0 + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));") + +(define_peephole2 + [(set (match_operand:DI 0 "register_operand" "") + (mult:DI (match_dup 0) + (match_operand:DI 1 "const_int_operand" "")))] + "exact_log2 (INTVAL (operands[1])) >= 0 + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (ashift:DI (match_dup 0) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (subreg:SI (mult:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "const_int_operand" "")) 0))] + "exact_log2 (INTVAL (operands[1])) >= 0 + && REGNO (operands[0]) == REGNO (operands[1]) + && peep2_regno_dead_p (0, FLAGS_REG)" + [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2))) + (clobber (reg:CC 17))])] + "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[2])));") + +;; The ESP adjustments can be done by the push and pop instructions. Resulting +;; code is shorter, since push is only 1 byte, while add imm, %esp 3 bytes. On +;; many CPUs it is also faster, since special hardware to avoid esp +;; dependencies is present. + +;; While some of these conversions may be done using splitters, we use peepholes +;; in order to allow combine_stack_adjustments pass to see nonobfuscated RTL. + +;; Convert prologue esp subtractions to push. +;; We need register to push. In order to keep verify_flow_info happy we have +;; two choices +;; - use scratch and clobber it in order to avoid dependencies +;; - use already live register +;; We can't use the second way right now, since there is no reliable way how to +;; verify that given register is live. First choice will also most likely in +;; fewer dependencies. On the place of esp adjustments it is very likely that +;; call clobbered registers are dead. We may want to use base pointer as an +;; alternative when no register is available later. + +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_SUB_ESP_4" + [(clobber (match_dup 0)) + (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (clobber (mem:BLK (scratch)))])]) + +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_SUB_ESP_8" + [(clobber (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (clobber (mem:BLK (scratch)))])]) + +;; Convert esp subtractions to push. +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4))) + (clobber (reg:CC 17))])] + "optimize_size || !TARGET_SUB_ESP_4" + [(clobber (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]) + +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (clobber (reg:CC 17))])] + "optimize_size || !TARGET_SUB_ESP_8" + [(clobber (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0)) + (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]) + +;; Convert epilogue deallocator to pop. +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_ADD_ESP_4" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (mem:BLK (scratch)))])] + "") + +;; Two pops case is tricky, since pop causes dependency on destination register. +;; We use two registers if available. +(define_peephole2 + [(match_scratch:SI 0 "r") + (match_scratch:SI 1 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_ADD_ESP_8" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (mem:BLK (scratch)))]) + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "") + +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (mem:BLK (scratch)))]) + (parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "") + +;; Convert esp additions to pop. +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4))) + (clobber (reg:CC 17))])] + "" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "") + +;; Two pops case is tricky, since pop causes dependency on destination register. +;; We use two registers if available. +(define_peephole2 + [(match_scratch:SI 0 "r") + (match_scratch:SI 1 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17))])] + "" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]) + (parallel [(set (match_dup 1) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "") + +(define_peephole2 + [(match_scratch:SI 0 "r") + (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8))) + (clobber (reg:CC 17))])] + "optimize_size" + [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]) + (parallel [(set (match_dup 0) (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])] + "") + +;; Convert compares with 1 to shorter inc/dec operations when CF is not +;; required and register dies. +(define_peephole2 + [(set (reg 17) + (compare (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "incdec_operand" "")))] + "ix86_match_ccmode (insn, CCGCmode) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCGC 17) + (compare:CCGC (match_dup 0) + (match_dup 1))) + (clobber (match_dup 0))])] + "") + +(define_peephole2 + [(set (reg 17) + (compare (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "incdec_operand" "")))] + "ix86_match_ccmode (insn, CCGCmode) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCGC 17) + (compare:CCGC (match_dup 0) + (match_dup 1))) + (clobber (match_dup 0))])] + "") + +(define_peephole2 + [(set (reg 17) + (compare (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "incdec_operand" "")))] + "ix86_match_ccmode (insn, CCGCmode) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCGC 17) + (compare:CCGC (match_dup 0) + (match_dup 1))) + (clobber (match_dup 0))])] + "") + +;; Convert compares with 128 to shorter add -128 +(define_peephole2 + [(set (reg 17) + (compare (match_operand:SI 0 "register_operand" "") + (const_int 128)))] + "ix86_match_ccmode (insn, CCGCmode) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCGC 17) + (compare:CCGC (match_dup 0) + (const_int 128))) + (clobber (match_dup 0))])] + "") + +(define_peephole2 + [(set (reg 17) + (compare (match_operand:HI 0 "register_operand" "") + (const_int 128)))] + "ix86_match_ccmode (insn, CCGCmode) + && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" + [(parallel [(set (reg:CCGC 17) + (compare:CCGC (match_dup 0) + (const_int 128))) + (clobber (match_dup 0))])] + "") + +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_SUB_ESP_4" + [(clobber (match_dup 0)) + (parallel [(set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (clobber (mem:BLK (scratch)))])]) + +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_SUB_ESP_8" + [(clobber (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (parallel [(set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (clobber (mem:BLK (scratch)))])]) + +;; Convert esp subtractions to push. +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -8))) + (clobber (reg:CC 17))])] + "optimize_size || !TARGET_SUB_ESP_4" + [(clobber (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0))]) + +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int -16))) + (clobber (reg:CC 17))])] + "optimize_size || !TARGET_SUB_ESP_8" + [(clobber (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0)) + (set (mem:DI (pre_dec:DI (reg:DI 7))) (match_dup 0))]) + +;; Convert epilogue deallocator to pop. +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_ADD_ESP_4" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (mem:BLK (scratch)))])] + "") + +;; Two pops case is tricky, since pop causes dependency on destination register. +;; We use two registers if available. +(define_peephole2 + [(match_scratch:DI 0 "r") + (match_scratch:DI 1 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size || !TARGET_ADD_ESP_8" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (mem:BLK (scratch)))]) + (parallel [(set (match_dup 1) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] + "") + +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17)) + (clobber (mem:BLK (scratch)))])] + "optimize_size" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (mem:BLK (scratch)))]) + (parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] + "") + +;; Convert esp additions to pop. +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8))) + (clobber (reg:CC 17))])] + "" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] + "") + +;; Two pops case is tricky, since pop causes dependency on destination register. +;; We use two registers if available. +(define_peephole2 + [(match_scratch:DI 0 "r") + (match_scratch:DI 1 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17))])] + "" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))]) + (parallel [(set (match_dup 1) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] + "") + +(define_peephole2 + [(match_scratch:DI 0 "r") + (parallel [(set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 16))) + (clobber (reg:CC 17))])] + "optimize_size" + [(parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))]) + (parallel [(set (match_dup 0) (mem:DI (reg:DI 7))) + (set (reg:DI 7) (plus:DI (reg:DI 7) (const_int 8)))])] + "") + +;; Call-value patterns last so that the wildcard operand does not +;; disrupt insn-recog's switch tables. + +(define_insn "*call_value_pop_0" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "constant_call_address_operand" "")) + (match_operand:SI 2 "" ""))) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 3 "immediate_operand" "")))] + "!TARGET_64BIT" +{ + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_pop_1" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) + (match_operand:SI 2 "" ""))) + (set (reg:SI 7) (plus:SI (reg:SI 7) + (match_operand:SI 3 "immediate_operand" "i")))] + "!TARGET_64BIT" +{ + if (constant_call_address_operand (operands[1], QImode)) + { + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; + } + if (SIBLING_CALL_P (insn)) + return "jmp\t%A1"; + else + return "call\t%A1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_0" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "constant_call_address_operand" "")) + (match_operand:SI 2 "" "")))] + "!TARGET_64BIT" +{ + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_0_rex64" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:DI 1 "constant_call_address_operand" "")) + (match_operand:DI 2 "const_int_operand" "")))] + "TARGET_64BIT" { - load_pic_register (1); + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_1" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) + (match_operand:SI 2 "" "")))] + "!TARGET_64BIT" +{ + if (constant_call_address_operand (operands[1], QImode)) + { + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; + } + if (SIBLING_CALL_P (insn)) + return "jmp\t%*%1"; + else + return "call\t%*%1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_1_rex64" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) + (match_operand:DI 2 "" "")))] + "TARGET_64BIT" +{ + if (constant_call_address_operand (operands[1], QImode)) + { + if (SIBLING_CALL_P (insn)) + return "jmp\t%P1"; + else + return "call\t%P1"; + } + if (SIBLING_CALL_P (insn)) + return "jmp\t%A1"; + else + return "call\t%A1"; +} + [(set_attr "type" "callv")]) + +(define_insn "trap" + [(trap_if (const_int 1) (const_int 5))] + "" + "int\t$5") + +;;; ix86 doesn't have conditional trap instructions, but we fake them +;;; for the sake of bounds checking. By emitting bounds checks as +;;; conditional traps rather than as conditional jumps around +;;; unconditional traps we avoid introducing spurious basic-block +;;; boundaries and facilitate elimination of redundant checks. In +;;; honor of the too-inflexible-for-BPs `bound' instruction, we use +;;; interrupt 5. +;;; +;;; FIXME: Static branch prediction rules for ix86 are such that +;;; forward conditional branches predict as untaken. As implemented +;;; below, pseudo conditional traps violate that rule. We should use +;;; .pushsection/.popsection to place all of the `int 5's in a special +;;; section loaded at the end of the text segment and branch forward +;;; there on bounds-failure, and then jump back immediately (in case +;;; the system chooses to ignore bounds violations, or to report +;;; violations and continue execution). + +(define_expand "conditional_trap" + [(trap_if (match_operator 0 "comparison_operator" + [(match_dup 2) (const_int 0)]) + (match_operand 1 "const_int_operand" ""))] + "" +{ + emit_insn (gen_rtx_TRAP_IF (VOIDmode, + ix86_expand_compare (GET_CODE (operands[0]), + NULL, NULL), + operands[1])); DONE; -}") +}) + +(define_insn "*conditional_trap_1" + [(trap_if (match_operator 0 "comparison_operator" + [(reg 17) (const_int 0)]) + (match_operand 1 "const_int_operand" ""))] + "" +{ + operands[2] = gen_label_rtx (); + output_asm_insn ("j%c0\t%l2\; int\t%1", operands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (operands[2])); + RET; +}) + + ;; Pentium III SIMD instructions. + +;; Moves for SSE/MMX regs. + +(define_insn "movv4sf_internal" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (match_operand:V4SF 1 "nonimmediate_operand" "xm,x"))] + "TARGET_SSE" + ;; @@@ let's try to use movaps here. + "movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "movv4si_internal" + [(set (match_operand:V4SI 0 "nonimmediate_operand" "=x,m") + (match_operand:V4SI 1 "nonimmediate_operand" "xm,x"))] + "TARGET_SSE" + ;; @@@ let's try to use movaps here. + "movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "movv8qi_internal" + [(set (match_operand:V8QI 0 "nonimmediate_operand" "=y,m") + (match_operand:V8QI 1 "nonimmediate_operand" "ym,y"))] + "TARGET_MMX" + "movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "movv4hi_internal" + [(set (match_operand:V4HI 0 "nonimmediate_operand" "=y,m") + (match_operand:V4HI 1 "nonimmediate_operand" "ym,y"))] + "TARGET_MMX" + "movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "movv2si_internal" + [(set (match_operand:V2SI 0 "nonimmediate_operand" "=y,m") + (match_operand:V2SI 1 "nonimmediate_operand" "ym,y"))] + "TARGET_MMX" + "movq\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "movv2sf_internal" + [(set (match_operand:V2SF 0 "nonimmediate_operand" "=y,m") + (match_operand:V2SF 1 "nonimmediate_operand" "ym,y"))] + "TARGET_3DNOW" + "movq\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_expand "movti" + [(set (match_operand:TI 0 "general_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "TARGET_SSE || TARGET_64BIT" +{ + if (TARGET_64BIT) + ix86_expand_move (TImode, operands); + else + ix86_expand_vector_move (TImode, operands); + DONE; +}) + +(define_expand "movv4sf" + [(set (match_operand:V4SF 0 "general_operand" "") + (match_operand:V4SF 1 "general_operand" ""))] + "TARGET_SSE" +{ + ix86_expand_vector_move (V4SFmode, operands); + DONE; +}) + +(define_expand "movv4si" + [(set (match_operand:V4SI 0 "general_operand" "") + (match_operand:V4SI 1 "general_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V4SImode, operands); + DONE; +}) + +(define_expand "movv2si" + [(set (match_operand:V2SI 0 "general_operand" "") + (match_operand:V2SI 1 "general_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V2SImode, operands); + DONE; +}) + +(define_expand "movv4hi" + [(set (match_operand:V4HI 0 "general_operand" "") + (match_operand:V4HI 1 "general_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V4HImode, operands); + DONE; +}) + +(define_expand "movv8qi" + [(set (match_operand:V8QI 0 "general_operand" "") + (match_operand:V8QI 1 "general_operand" ""))] + "TARGET_MMX" +{ + ix86_expand_vector_move (V8QImode, operands); + DONE; +}) + +(define_expand "movv2sf" + [(set (match_operand:V2SF 0 "general_operand" "") + (match_operand:V2SF 1 "general_operand" ""))] + "TARGET_3DNOW" +{ + ix86_expand_vector_move (V2SFmode, operands); + DONE; +}) + +(define_insn_and_split "*pushti" + [(set (match_operand:TI 0 "push_operand" "=<") + (match_operand:TI 1 "nonmemory_operand" "x"))] + "TARGET_SSE" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:TI (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "sse")]) + +(define_insn_and_split "*pushv4sf" + [(set (match_operand:V4SF 0 "push_operand" "=<") + (match_operand:V4SF 1 "nonmemory_operand" "x"))] + "TARGET_SSE" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:V4SF (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "sse")]) + +(define_insn_and_split "*pushv4si" + [(set (match_operand:V4SI 0 "push_operand" "=<") + (match_operand:V4SI 1 "nonmemory_operand" "x"))] + "TARGET_SSE" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16))) + (set (mem:V4SI (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "sse")]) + +(define_insn_and_split "*pushv2si" + [(set (match_operand:V2SI 0 "push_operand" "=<") + (match_operand:V2SI 1 "nonmemory_operand" "y"))] + "TARGET_MMX" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:V2SI (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "mmx")]) + +(define_insn_and_split "*pushv4hi" + [(set (match_operand:V4HI 0 "push_operand" "=<") + (match_operand:V4HI 1 "nonmemory_operand" "y"))] + "TARGET_MMX" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:V4HI (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "mmx")]) + +(define_insn_and_split "*pushv8qi" + [(set (match_operand:V8QI 0 "push_operand" "=<") + (match_operand:V8QI 1 "nonmemory_operand" "y"))] + "TARGET_MMX" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:V8QI (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "mmx")]) + +(define_insn_and_split "*pushv2sf" + [(set (match_operand:V2SF 0 "push_operand" "=<") + (match_operand:V2SF 1 "nonmemory_operand" "y"))] + "TARGET_3DNOW" + "#" + "" + [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8))) + (set (mem:V2SF (reg:SI 7)) (match_dup 1))] + "" + [(set_attr "type" "mmx")]) + +(define_insn "movti_internal" + [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:TI 1 "general_operand" "O,xm,x"))] + "TARGET_SSE && !TARGET_64BIT" + "@ + xorps\t%0, %0 + movaps\t{%1, %0|%0, %1} + movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "*movti_rex64" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o,x,mx,x") + (match_operand:TI 1 "general_operand" "riFo,riF,O,x,m"))] + "TARGET_64BIT + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "@ + # + # + xorps\t%0, %0 + movaps\\t{%1, %0|%0, %1} + movaps\\t{%1, %0|%0, %1}" + [(set_attr "type" "*,*,sse,sse,sse") + (set_attr "mode" "TI")]) + +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "reload_completed && !SSE_REG_P (operands[0]) + && !SSE_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +;; These two patterns are useful for specifying exactly whether to use +;; movaps or movups +(define_insn "sse_movaps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm,x")] 38))] + "TARGET_SSE" + "@ + movaps\t{%1, %0|%0, %1} + movaps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movups" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm,x")] 39))] + "TARGET_SSE" + "@ + movups\t{%1, %0|%0, %1} + movups\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + + +;; SSE Strange Moves. + +(define_insn "sse_movmskps" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V4SF 1 "register_operand" "x")] 33))] + "TARGET_SSE" + "movmskps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_pmovmskb" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:V8QI 1 "register_operand" "y")] 33))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmovmskb\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_maskmovq" + [(set (mem:V8QI (match_operand:SI 0 "register_operand" "D")) + (unspec:V8QI [(match_operand:V8QI 1 "register_operand" "y") + (match_operand:V8QI 2 "register_operand" "y")] 32))] + "TARGET_SSE || TARGET_3DNOW_A" + ;; @@@ check ordering of operands in intel/nonintel syntax + "maskmovq\t{%2, %1|%1, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movntv4sf" + [(set (match_operand:V4SF 0 "memory_operand" "=m") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "x")] 34))] + "TARGET_SSE" + "movntps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movntdi" + [(set (match_operand:DI 0 "memory_operand" "=m") + (unspec:DI [(match_operand:DI 1 "register_operand" "y")] 34))] + "TARGET_SSE || TARGET_3DNOW_A" + "movntq\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movhlps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])) + (const_int 3)))] + "TARGET_SSE" + "movhlps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movlhps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 3) + (const_int 0) + (const_int 1)])) + (const_int 12)))] + "TARGET_SSE" + "movlhps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movhps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (vec_merge:V4SF + (match_operand:V4SF 1 "nonimmediate_operand" "0,0") + (match_operand:V4SF 2 "nonimmediate_operand" "m,x") + (const_int 12)))] + "TARGET_SSE + && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)" + "movhps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movlps" + [(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,m") + (vec_merge:V4SF + (match_operand:V4SF 1 "nonimmediate_operand" "0,0") + (match_operand:V4SF 2 "nonimmediate_operand" "m,x") + (const_int 3)))] + "TARGET_SSE + && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)" + "movlps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_loadss" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "memory_operand" "m") + (vec_duplicate:V4SF (float:SF (const_int 0))) + (const_int 1)))] + "TARGET_SSE" + "movss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_movss" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x") + (const_int 1)))] + "TARGET_SSE" + "movss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_storess" + [(set (match_operand:SF 0 "memory_operand" "=m") + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)])))] + "TARGET_SSE" + "movss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_shufps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm") + (match_operand:SI 3 "immediate_operand" "i")] 41))] + "TARGET_SSE" + ;; @@@ check operand order for intel/nonintel syntax + "shufps\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "sse")]) + + +;; SSE arithmetic + +(define_insn "addv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (plus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "addps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmaddv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (plus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "addss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "subv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (minus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "subps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmsubv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (minus:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "subss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "mulv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (mult:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "mulps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmmulv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (mult:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "mulss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "divv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (div:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "divps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmdivv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (div:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "divss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + + +;; SSE square root/reciprocal + +(define_insn "rcpv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 42))] + "TARGET_SSE" + "rcpps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "vmrcpv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 42) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "rcpss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "rsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF + [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 43))] + "TARGET_SSE" + "rsqrtps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "vmrsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (unspec:V4SF [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 43) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "rsqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (sqrt:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "sqrtps\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "vmsqrtv4sf2" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (sqrt:V4SF (match_operand:V4SF 1 "nonimmediate_operand" "xm")) + (match_operand:V4SF 2 "register_operand" "0") + (const_int 1)))] + "TARGET_SSE" + "sqrtss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +;; SSE logical operations. + +;; These are not called andti3 etc. because we really really don't want +;; the compiler to widen DImode ands to TImode ands and then try to move +;; into DImode subregs of SSE registers, and them together, and move out +;; of DImode subregs again! + +(define_insn "*sse_andti3_df_1" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (and:TI (subreg:TI (match_operand:DF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:DF 2 "register_operand" "Y") 0)))] + "TARGET_SSE2" + "andpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_andti3_df_2" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (and:TI (subreg:TI (match_operand:DF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2" + "andpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_andti3_sf_1" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (and:TI (subreg:TI (match_operand:SF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:SF 2 "register_operand" "x") 0)))] + "TARGET_SSE" + "andps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_andti3_sf_2" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (and:TI (subreg:TI (match_operand:SF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "andps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_andti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE && !TARGET_SSE2" + "andps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_andti3_sse2" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pand\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_nandti3_df" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (and:TI (not:TI (subreg:TI (match_operand:DF 1 "register_operand" "0") 0)) + (match_operand:TI 2 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2" + "andnpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_nandti3_sf" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (and:TI (not:TI (subreg:TI (match_operand:SF 1 "register_operand" "0") 0)) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "andnps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_nandti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (not:TI (match_operand:TI 1 "register_operand" "0")) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE && !TARGET_SSE2" + "andnps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_nandti3_sse2" + [(set (match_operand:TI 0 "register_operand" "=x") + (and:TI (not:TI (match_operand:TI 1 "register_operand" "0")) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pnand\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_iorti3_df_1" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (ior:TI (subreg:TI (match_operand:DF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:DF 2 "register_operand" "Y") 0)))] + "TARGET_SSE2" + "orpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_iorti3_df_2" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (ior:TI (subreg:TI (match_operand:DF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2" + "orpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_iorti3_sf_1" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (ior:TI (subreg:TI (match_operand:SF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:SF 2 "register_operand" "x") 0)))] + "TARGET_SSE" + "orps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_iorti3_sf_2" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (ior:TI (subreg:TI (match_operand:SF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "orps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_iorti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (ior:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE && !TARGET_SSE2" + "orps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_iorti3_sse2" + [(set (match_operand:TI 0 "register_operand" "=x") + (ior:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "por\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_xorti3_df_1" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (xor:TI (subreg:TI (match_operand:DF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:DF 2 "register_operand" "Y") 0)))] + "TARGET_SSE2" + "xorpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_xorti3_df_2" + [(set (subreg:TI (match_operand:DF 0 "register_operand" "=Y") 0) + (xor:TI (subreg:TI (match_operand:DF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "Ym")))] + "TARGET_SSE2" + "xorpd\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_xorti3_sf_1" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (xor:TI (subreg:TI (match_operand:SF 1 "register_operand" "%0") 0) + (subreg:TI (match_operand:SF 2 "register_operand" "x") 0)))] + "TARGET_SSE" + "xorps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_xorti3_sf_2" + [(set (subreg:TI (match_operand:SF 0 "register_operand" "=x") 0) + (xor:TI (subreg:TI (match_operand:SF 1 "register_operand" "0") 0) + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "xorps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_xorti3" + [(set (match_operand:TI 0 "register_operand" "=x") + (xor:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE && !TARGET_SSE2" + "xorps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "*sse_xorti3_sse2" + [(set (match_operand:TI 0 "register_operand" "=x") + (xor:TI (match_operand:TI 1 "register_operand" "%0") + (match_operand:TI 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE2" + "pxor\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +;; Use xor, but don't show input operands so they aren't live before +;; this insn. +(define_insn "sse_clrv4sf" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (unspec:V4SF [(const_int 0)] 45))] + "TARGET_SSE" + "xorps\t{%0, %0|%0, %0}" + [(set_attr "type" "sse") + (set_attr "memory" "none")]) + +;; SSE mask-generating compares + +(define_insn "maskcmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")]))] + "TARGET_SSE" + "cmp%D3ps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "maskncmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (not:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")])))] + "TARGET_SSE" +{ + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordps\t{%2, %0|%0, %2}"; + else + return "cmpn%D3ps\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "sse")]) + +(define_insn "vmmaskcmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")]) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "cmp%D3ss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmmaskncmpv4sf3" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (vec_merge:V4SI + (not:V4SI + (match_operator:V4SI 3 "sse_comparison_operator" + [(match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "register_operand" "x")])) + (subreg:V4SI (match_dup 1) 0) + (const_int 1)))] + "TARGET_SSE" +{ + if (GET_CODE (operands[3]) == UNORDERED) + return "cmpordss\t{%2, %0|%0, %2}"; + else + return "cmpn%D3ss\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "sse")]) + +(define_insn "sse_comi" + [(set (reg:CCFP 17) + (match_operator:CCFP 2 "sse_comparison_operator" + [(vec_select:SF + (match_operand:V4SF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)]))]))] + "TARGET_SSE" + "comiss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "sse_ucomi" + [(set (reg:CCFPU 17) + (match_operator:CCFPU 2 "sse_comparison_operator" + [(vec_select:SF + (match_operand:V4SF 0 "register_operand" "x") + (parallel [(const_int 0)])) + (vec_select:SF + (match_operand:V4SF 1 "register_operand" "x") + (parallel [(const_int 0)]))]))] + "TARGET_SSE" + "ucomiss\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + + +;; SSE unpack + +(define_insn "sse_unpckhps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (vec_select:V4SF (match_operand:V4SF 1 "register_operand" "0") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (const_int 5)))] + "TARGET_SSE" + "unpckhps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sse_unpcklps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (vec_select:V4SF (match_operand:V4SF 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (vec_select:V4SF (match_operand:V4SF 2 "register_operand" "x") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (const_int 5)))] + "TARGET_SSE" + "unpcklps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + + +;; SSE min/max + +(define_insn "smaxv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (smax:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "maxps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmsmaxv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (smax:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "maxss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sminv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (smin:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")))] + "TARGET_SSE" + "minps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "vmsminv4sf3" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (smin:V4SF (match_operand:V4SF 1 "register_operand" "0") + (match_operand:V4SF 2 "nonimmediate_operand" "xm")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "minss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + + +;; SSE <-> integer/MMX conversions + +(define_insn "cvtpi2ps" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_duplicate:V4SF + (float:V2SF (match_operand:V2SI 2 "nonimmediate_operand" "ym"))) + (const_int 12)))] + "TARGET_SSE" + "cvtpi2ps\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "cvtps2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI + (fix:V4SI (match_operand:V4SF 1 "nonimmediate_operand" "xm")) + (parallel [(const_int 0) (const_int 1)])))] + "TARGET_SSE" + "cvtps2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "cvttps2pi" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI + (unspec:V4SI [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 30) + (parallel [(const_int 0) (const_int 1)])))] + "TARGET_SSE" + "cvttps2pi\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "cvtsi2ss" + [(set (match_operand:V4SF 0 "register_operand" "=x") + (vec_merge:V4SF + (match_operand:V4SF 1 "register_operand" "0") + (vec_duplicate:V4SF + (float:SF (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (const_int 14)))] + "TARGET_SSE" + "cvtsi2ss\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "cvtss2si" + [(set (match_operand:SI 0 "register_operand" "=r") + (vec_select:SI + (fix:V4SI (match_operand:V4SF 1 "nonimmediate_operand" "xm")) + (parallel [(const_int 0)])))] + "TARGET_SSE" + "cvtss2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + +(define_insn "cvttss2si" + [(set (match_operand:SI 0 "register_operand" "=r") + (vec_select:SI + (unspec:V4SI [(match_operand:V4SF 1 "nonimmediate_operand" "xm")] 30) + (parallel [(const_int 0)])))] + "TARGET_SSE" + "cvttss2si\t{%1, %0|%0, %1}" + [(set_attr "type" "sse")]) + + +;; MMX insns + +;; MMX arithmetic + +(define_insn "addv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (plus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "addv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (plus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "addv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (plus:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ssaddv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ss_plus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddsb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ssaddv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ss_plus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "usaddv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (us_plus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddusb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "usaddv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (us_plus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "paddusw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "subv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "subv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "subv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (minus:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "sssubv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ss_minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubsb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "sssubv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ss_minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubsw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ussubv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (us_minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubusb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ussubv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (us_minus:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "psubusw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mulv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (mult:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pmullw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "smulv4hi3_highpart" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (mult:V4SI (sign_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (sign_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (const_int 16))))] + "TARGET_MMX" + "pmulhw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "umulv4hi3_highpart" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (mult:V4SI (zero_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (zero_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (const_int 16))))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmulhuw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_pmaddwd" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (plus:V2SI + (mult:V2SI + (sign_extend:V2SI + (vec_select:V2HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 0) (const_int 2)]))) + (sign_extend:V2SI + (vec_select:V2HI (match_operand:V4HI 2 "nonimmediate_operand" "ym") + (parallel [(const_int 0) (const_int 2)])))) + (mult:V2SI + (sign_extend:V2SI (vec_select:V2HI (match_dup 1) + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2SI (vec_select:V2HI (match_dup 2) + (parallel [(const_int 1) + (const_int 3)]))))))] + "TARGET_MMX" + "pmaddwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + + +;; MMX logical operations +;; Note we don't want to declare these as regular iordi3 insns to prevent +;; normal code that also wants to use the FPU from getting broken. +;; The UNSPECs are there to prevent the combiner from getting overly clever. +(define_insn "mmx_iordi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(ior:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] 45))] + "TARGET_MMX" + "por\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_xordi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(xor:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] 45))] + "TARGET_MMX" + "pxor\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx") + (set_attr "memory" "none")]) + +;; Same as pxor, but don't show input operands so that we don't think +;; they are live. +(define_insn "mmx_clrdi" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI [(const_int 0)] 45))] + "TARGET_MMX" + "pxor\t{%0, %0|%0, %0}" + [(set_attr "type" "mmx") + (set_attr "memory" "none")]) + +(define_insn "mmx_anddi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(and:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonimmediate_operand" "ym"))] 45))] + "TARGET_MMX" + "pand\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_nanddi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(and:DI (not:DI (match_operand:DI 1 "register_operand" "0")) + (match_operand:DI 2 "nonimmediate_operand" "ym"))] 45))] + "TARGET_MMX" + "pandn\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + + +;; MMX unsigned averages/sum of absolute differences + +(define_insn "mmx_uavgv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (ashiftrt:V8QI + (plus:V8QI (plus:V8QI + (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")) + (vec_const:V8QI (parallel [(const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1) + (const_int 1)]))) + (const_int 1)))] + "TARGET_SSE || TARGET_3DNOW_A" + "pavgb\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_uavgv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashiftrt:V4HI + (plus:V4HI (plus:V4HI + (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")) + (vec_const:V4HI (parallel [(const_int 1) + (const_int 1) + (const_int 1) + (const_int 1)]))) + (const_int 1)))] + "TARGET_SSE || TARGET_3DNOW_A" + "pavgw\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_psadbw" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (abs:V8QI (minus:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym"))))] + "TARGET_SSE || TARGET_3DNOW_A" + "psadbw\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + + +;; MMX insert/extract/shuffle + +(define_insn "mmx_pinsrw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI (match_operand:V4HI 1 "register_operand" "0") + (vec_duplicate:V4HI + (truncate:HI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (match_operand:SI 3 "immediate_operand" "i")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pinsrw\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_pextrw" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (vec_select:HI (match_operand:V4HI 1 "register_operand" "y") + (parallel + [(match_operand:SI 2 "immediate_operand" "i")]))))] + "TARGET_SSE || TARGET_3DNOW_A" + "pextrw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sse")]) + +(define_insn "mmx_pshufw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (unspec:V4HI [(match_operand:V4HI 1 "register_operand" "0") + (match_operand:SI 2 "immediate_operand" "i")] 41))] + "TARGET_SSE || TARGET_3DNOW_A" + "pshufw\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sse")]) + + +;; MMX mask-generating comparisons + +(define_insn "eqv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (eq:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "eqv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (eq:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "eqv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (eq:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpeqd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "gtv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (gt:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "gtv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (gt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "gtv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (gt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:V2SI 2 "nonimmediate_operand" "ym")))] + "TARGET_MMX" + "pcmpgtd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + + +;; MMX max/min insns + +(define_insn "umaxv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (umax:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmaxub\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "smaxv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (smax:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pmaxsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "uminv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (umin:V8QI (match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pminub\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + +(define_insn "sminv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (smin:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:V4HI 2 "nonimmediate_operand" "ym")))] + "TARGET_SSE || TARGET_3DNOW_A" + "pminsw\t{%2, %0|%0, %2}" + [(set_attr "type" "sse")]) + + +;; MMX shifts + +(define_insn "ashrv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashiftrt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psraw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ashrv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ashiftrt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrad\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "lshrv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (lshiftrt:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrlw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "lshrv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (lshiftrt:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psrld\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +;; See logical MMX insns. +(define_insn "mmx_lshrdi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi"))] 45))] + "TARGET_MMX" + "psrlq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ashlv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (ashift:V4HI (match_operand:V4HI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "psllw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "ashlv2si3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ashift:V2SI (match_operand:V2SI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi")))] + "TARGET_MMX" + "pslld\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +;; See logical MMX insns. +(define_insn "mmx_ashldi3" + [(set (match_operand:DI 0 "register_operand" "=y") + (unspec:DI + [(ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "nonmemory_operand" "yi"))] 45))] + "TARGET_MMX" + "psllq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + + +;; MMX pack/unpack insns. + +(define_insn "mmx_packsswb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_concat:V8QI + (ss_truncate:V4QI (match_operand:V4HI 1 "register_operand" "0")) + (ss_truncate:V4QI (match_operand:V4HI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packsswb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_packssdw" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_concat:V4HI + (ss_truncate:V2HI (match_operand:V2SI 1 "register_operand" "0")) + (ss_truncate:V2HI (match_operand:V2SI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packssdw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_packuswb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_concat:V8QI + (us_truncate:V4QI (match_operand:V4HI 1 "register_operand" "0")) + (us_truncate:V4QI (match_operand:V4HI 2 "register_operand" "y"))))] + "TARGET_MMX" + "packuswb\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpckhbw" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_merge:V8QI + (vec_select:V8QI (match_operand:V8QI 1 "register_operand" "0") + (parallel [(const_int 4) + (const_int 0) + (const_int 5) + (const_int 1) + (const_int 6) + (const_int 2) + (const_int 7) + (const_int 3)])) + (vec_select:V8QI (match_operand:V8QI 2 "register_operand" "y") + (parallel [(const_int 0) + (const_int 4) + (const_int 1) + (const_int 5) + (const_int 2) + (const_int 6) + (const_int 3) + (const_int 7)])) + (const_int 85)))] + "TARGET_MMX" + "punpckhbw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpckhwd" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI + (vec_select:V4HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (vec_select:V4HI (match_operand:V4HI 2 "register_operand" "y") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (const_int 5)))] + "TARGET_MMX" + "punpckhwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpckhdq" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_merge:V2SI + (vec_select:V2SI (match_operand:V2SI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 1)])) + (vec_select:V2SI (match_operand:V2SI 2 "register_operand" "y") + (parallel [(const_int 1) + (const_int 0)])) + (const_int 1)))] + "TARGET_MMX" + "punpckhdq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpcklbw" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (vec_merge:V8QI + (vec_select:V8QI (match_operand:V8QI 1 "register_operand" "0") + (parallel [(const_int 0) + (const_int 4) + (const_int 1) + (const_int 5) + (const_int 2) + (const_int 6) + (const_int 3) + (const_int 7)])) + (vec_select:V8QI (match_operand:V8QI 2 "register_operand" "y") + (parallel [(const_int 4) + (const_int 0) + (const_int 5) + (const_int 1) + (const_int 6) + (const_int 2) + (const_int 7) + (const_int 3)])) + (const_int 85)))] + "TARGET_MMX" + "punpcklbw\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpcklwd" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (vec_merge:V4HI + (vec_select:V4HI (match_operand:V4HI 1 "register_operand" "0") + (parallel [(const_int 2) + (const_int 0) + (const_int 3) + (const_int 1)])) + (vec_select:V4HI (match_operand:V4HI 2 "register_operand" "y") + (parallel [(const_int 0) + (const_int 2) + (const_int 1) + (const_int 3)])) + (const_int 5)))] + "TARGET_MMX" + "punpcklwd\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mmx_punpckldq" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_merge:V2SI + (vec_select:V2SI (match_operand:V2SI 1 "register_operand" "0") + (parallel [(const_int 1) + (const_int 0)])) + (vec_select:V2SI (match_operand:V2SI 2 "register_operand" "y") + (parallel [(const_int 0) + (const_int 1)])) + (const_int 1)))] + "TARGET_MMX" + "punpckldq\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + + +;; Miscellaneous stuff + +(define_insn "emms" + [(unspec_volatile [(const_int 0)] 31) + (clobber (reg:XF 8)) + (clobber (reg:XF 9)) + (clobber (reg:XF 10)) + (clobber (reg:XF 11)) + (clobber (reg:XF 12)) + (clobber (reg:XF 13)) + (clobber (reg:XF 14)) + (clobber (reg:XF 15)) + (clobber (reg:DI 29)) + (clobber (reg:DI 30)) + (clobber (reg:DI 31)) + (clobber (reg:DI 32)) + (clobber (reg:DI 33)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36))] + "TARGET_MMX" + "emms" + [(set_attr "type" "mmx") + (set_attr "memory" "unknown")]) + +(define_insn "ldmxcsr" + [(unspec_volatile [(match_operand:SI 0 "memory_operand" "m")] 37)] + "TARGET_MMX" + "ldmxcsr\t%0" + [(set_attr "type" "mmx") + (set_attr "memory" "load")]) + +(define_insn "stmxcsr" + [(set (match_operand:SI 0 "memory_operand" "=m") + (unspec_volatile:SI [(const_int 0)] 40))] + "TARGET_MMX" + "stmxcsr\t%0" + [(set_attr "type" "mmx") + (set_attr "memory" "store")]) + +(define_expand "sfence" + [(set (match_dup 0) + (unspec:BLK [(match_dup 0)] 44))] + "TARGET_SSE || TARGET_3DNOW_A" +{ + operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (operands[0]) = 1; +}) + +(define_insn "*sfence_insn" + [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(match_dup 0)] 44))] + "TARGET_SSE || TARGET_3DNOW_A" + "sfence" + [(set_attr "type" "sse") + (set_attr "memory" "unknown")]) + +(define_expand "sse_prologue_save" + [(parallel [(set (match_operand:BLK 0 "" "") + (unspec:BLK [(reg:DI 21) + (reg:DI 22) + (reg:DI 23) + (reg:DI 24) + (reg:DI 25) + (reg:DI 26) + (reg:DI 27) + (reg:DI 28)] 13)) + (use (match_operand:DI 1 "register_operand" "")) + (use (match_operand:DI 2 "immediate_operand" "")) + (use (label_ref:DI (match_operand 3 "" "")))])] + "TARGET_64BIT" + "") + +(define_insn "*sse_prologue_save_insn" + [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R") + (match_operand:DI 4 "const_int_operand" "n"))) + (unspec:BLK [(reg:DI 21) + (reg:DI 22) + (reg:DI 23) + (reg:DI 24) + (reg:DI 25) + (reg:DI 26) + (reg:DI 27) + (reg:DI 28)] 13)) + (use (match_operand:DI 1 "register_operand" "r")) + (use (match_operand:DI 2 "const_int_operand" "i")) + (use (label_ref:DI (match_operand 3 "" "X")))] + "TARGET_64BIT + && INTVAL (operands[4]) + SSE_REGPARM_MAX * 16 - 16 < 128 + && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128" + "* +{ + int i; + operands[0] = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, operands[0], operands[4])); + output_asm_insn (\"jmp\\t%A1\", operands); + for (i = SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--) + { + operands[4] = adjust_address (operands[0], DImode, i*16); + operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i)); + PUT_MODE (operands[4], TImode); + if (GET_CODE (XEXP (operands[0], 0)) != PLUS) + output_asm_insn (\"rex\", operands); + output_asm_insn (\"movaps\\t{%5, %4|%4, %5}\", operands); + } + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[3])); + RET; +} + " + [(set_attr "type" "other") + (set_attr "length_immediate" "0") + (set_attr "length_address" "0") + (set_attr "length" "135") + (set_attr "memory" "store") + (set_attr "modrm" "0") + (set_attr "mode" "DI")]) + +;; 3Dnow! instructions + +(define_insn "addv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (plus:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfadd\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "subv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (minus:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfsub\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "subrv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (minus:V2SF (match_operand:V2SF 2 "nonimmediate_operand" "ym") + (match_operand:V2SF 1 "register_operand" "0")))] + "TARGET_3DNOW" + "pfsubr\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "gtv2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (gt:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpgt\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "gev2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (ge:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpge\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "eqv2sf3" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (eq:V2SI (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfcmpeq\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfmaxv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (smax:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmax\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfminv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (smin:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmin\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "mulv2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (mult:V2SF (match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pfmul\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "femms" + [(unspec_volatile [(const_int 0)] 46) + (clobber (reg:XF 8)) + (clobber (reg:XF 9)) + (clobber (reg:XF 10)) + (clobber (reg:XF 11)) + (clobber (reg:XF 12)) + (clobber (reg:XF 13)) + (clobber (reg:XF 14)) + (clobber (reg:XF 15)) + (clobber (reg:DI 29)) + (clobber (reg:DI 30)) + (clobber (reg:DI 31)) + (clobber (reg:DI 32)) + (clobber (reg:DI 33)) + (clobber (reg:DI 34)) + (clobber (reg:DI 35)) + (clobber (reg:DI 36))] + "TARGET_3DNOW" + "femms" + [(set_attr "type" "mmx")]) + +(define_insn "pf2id" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pf2id\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "pf2iw" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (sign_extend:V2SI + (ss_truncate:V2HI + (fix:V2SI (match_operand:V2SF 1 "nonimmediate_operand" "ym")))))] + "TARGET_3DNOW_A" + "pf2iw\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "pfacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (plus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (plus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW" + "pfacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfnacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (minus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (minus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW_A" + "pfnacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfpnacc" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_concat:V2SF + (minus:SF + (vec_select:SF (match_operand:V2SF 1 "register_operand" "0") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 1) + (parallel [(const_int 1)]))) + (plus:SF + (vec_select:SF (match_operand:V2SF 2 "nonimmediate_operand" "y") + (parallel [(const_int 0)])) + (vec_select:SF (match_dup 2) + (parallel [(const_int 1)])))))] + "TARGET_3DNOW_A" + "pfpnacc\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pi2fw" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (float:V2SF + (vec_concat:V2SI + (sign_extend:SI + (truncate:HI + (vec_select:SI (match_operand:V2SI 1 "nonimmediate_operand" "ym") + (parallel [(const_int 0)])))) + (sign_extend:SI + (truncate:HI + (vec_select:SI (match_dup 1) + (parallel [(const_int 1)])))))))] + "TARGET_3DNOW_A" + "pi2fw\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "floatv2si2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (float:V2SF (match_operand:V2SI 1 "nonimmediate_operand" "ym")))] + "TARGET_3DNOW" + "pi2fd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +;; This insn is identical to pavgb in operation, but the opcode is +;; different. To avoid accidentally matching pavgb, use an unspec. + +(define_insn "pavgusb" + [(set (match_operand:V8QI 0 "register_operand" "=y") + (unspec:V8QI + [(match_operand:V8QI 1 "register_operand" "0") + (match_operand:V8QI 2 "nonimmediate_operand" "ym")] 49))] + "TARGET_3DNOW" + "pavgusb\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +;; 3DNow reciprical and sqrt + +(define_insn "pfrcpv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "nonimmediate_operand" "ym")] 50))] + "TARGET_3DNOW" + "pfrcp\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "pfrcpit1v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] 51))] + "TARGET_3DNOW" + "pfrcpit1\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfrcpit2v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] 52))] + "TARGET_3DNOW" + "pfrcpit2\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pfrsqrtv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "nonimmediate_operand" "ym")] 53))] + "TARGET_3DNOW" + "pfrsqrt\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "pfrsqit1v2sf3" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (unspec:V2SF [(match_operand:V2SF 1 "register_operand" "0") + (match_operand:V2SF 2 "nonimmediate_operand" "ym")] 54))] + "TARGET_3DNOW" + "pfrsqit1\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pmulhrwv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=y") + (truncate:V4HI + (lshiftrt:V4SI + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (match_operand:V4HI 1 "register_operand" "0")) + (sign_extend:V4SI + (match_operand:V4HI 2 "nonimmediate_operand" "ym"))) + (vec_const:V4SI + (parallel [(const_int 32768) + (const_int 32768) + (const_int 32768) + (const_int 32768)]))) + (const_int 16))))] + "TARGET_3DNOW" + "pmulhrw\\t{%2, %0|%0, %2}" + [(set_attr "type" "mmx")]) + +(define_insn "pswapdv2si2" + [(set (match_operand:V2SI 0 "register_operand" "=y") + (vec_select:V2SI (match_operand:V2SI 1 "nonimmediate_operand" "ym") + (parallel [(const_int 1) (const_int 0)])))] + "TARGET_3DNOW_A" + "pswapd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_insn "pswapdv2sf2" + [(set (match_operand:V2SF 0 "register_operand" "=y") + (vec_select:V2SF (match_operand:V2SF 1 "nonimmediate_operand" "ym") + (parallel [(const_int 1) (const_int 0)])))] + "TARGET_3DNOW_A" + "pswapd\\t{%1, %0|%0, %1}" + [(set_attr "type" "mmx")]) + +(define_expand "prefetch" + [(prefetch (match_operand:SI 0 "address_operand" "") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" ""))] + "TARGET_PREFETCH_SSE || TARGET_3DNOW" +{ + int rw = INTVAL (operands[1]); + int locality = INTVAL (operands[2]); + + if (rw != 0 && rw != 1) + abort (); + if (locality < 0 || locality > 3) + abort (); + + /* Use 3dNOW prefetch in case we are asking for write prefetch not + suported by SSE counterpart or the SSE prefetch is not available + (K6 machines). Otherwise use SSE prefetch as it allows specifying + of locality. */ + if (TARGET_3DNOW && (!TARGET_PREFETCH_SSE || rw)) + operands[2] = GEN_INT (3); + else + operands[1] = const0_rtx; +}) + +(define_insn "*prefetch_sse" + [(prefetch (match_operand:SI 0 "address_operand" "p") + (const_int 0) + (match_operand:SI 1 "const_int_operand" ""))] + "TARGET_PREFETCH_SSE" +{ + static const char * const patterns[4] = { + "prefetchnta\t%a0", "prefetcht2\t%a0", "prefetcht1\t%a0", "prefetcht0\t%a0" + }; + + int locality = INTVAL (operands[1]); + if (locality < 0 || locality > 3) + abort (); + + return patterns[locality]; +} + [(set_attr "type" "sse")]) + +(define_insn "*prefetch_3dnow" + [(prefetch (match_operand:SI 0 "address_operand" "p") + (match_operand:SI 1 "const_int_operand" "n") + (const_int 3))] + "TARGET_3DNOW" +{ + if (INTVAL (operands[1]) == 0) + return "prefetch\t%a0"; + else + return "prefetchw\t%a0"; +} + [(set_attr "type" "mmx")]) diff --git a/contrib/gcc/config/i386/i386elf.h b/contrib/gcc/config/i386/i386elf.h new file mode 100644 index 0000000..ddf19b6 --- /dev/null +++ b/contrib/gcc/config/i386/i386elf.h @@ -0,0 +1,136 @@ +/* Target definitions for GNU compiler for Intel 80386 using ELF + Copyright (C) 1988, 1991, 1995, 2000, 2001 Free Software Foundation, Inc. + + Derived from sysv4.h 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. */ + +/* Use stabs instead of DWARF debug format. */ +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (i386 bare ELF target)"); + +/* By default, target has a 80387, uses IEEE compatible arithmetic, + and returns float values in the 387. */ + +#define TARGET_SUBTARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS) + +/* The ELF 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 \ + || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8)) + +/* 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 "" + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu)" + +#define ENDFILE_SPEC "crtend.o%s" + +#define STARTFILE_SPEC "%{!shared: \ + %{!symbolic: \ + %{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}\ + crtbegin.o%s" + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) + +/* 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 const unsigned char *_ascii_bytes = \ + (const unsigned char *) (STR); \ + register const unsigned char *limit = _ascii_bytes + (LENGTH); \ + register unsigned bytes_in_chunk = 0; \ + for (; _ascii_bytes < limit; _ascii_bytes++) \ + { \ + register const 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) <= (long) 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) + +#define LOCAL_LABEL_PREFIX "." + +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section + +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as + uninitialized global data. If not defined, and neither + `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, + uninitialized global data will be output in the data section if + `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be + used. */ +#undef BSS_SECTION_ASM_OP +#define BSS_SECTION_ASM_OP "\t.section\t.bss" + +/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a + separate, explicit argument. If you define this macro, it is used + in place of `ASM_OUTPUT_BSS', and gives you more flexibility in + handling the required alignment of the variable. The alignment is + specified as the number of bits. + + Try to use function `asm_output_aligned_bss' defined in file + `varasm.c' when defining this macro. */ +#undef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) diff --git a/contrib/gcc/config/i386/interix.c b/contrib/gcc/config/i386/interix.c index 40062c7..8ea2c6e 100644 --- a/contrib/gcc/config/i386/interix.c +++ b/contrib/gcc/config/i386/interix.c @@ -31,14 +31,14 @@ Boston, MA 02111-1307, USA. */ suffix consisting of an atsign (@) followed by the number of bytes of arguments */ -char * +const 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)); + const char *const asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); char *newsym; if (TYPE_ARG_TYPES (TREE_TYPE (decl))) @@ -68,7 +68,7 @@ gen_stdcall_suffix (decl) #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. */ + MK. */ /* Cover function for UNIQUE_SECTION. */ @@ -78,7 +78,8 @@ i386_pe_unique_section (decl, reloc) int reloc; { int len; - char *name,*string,*prefix; + const char *name; + char *string,*prefix; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); /* Strip off any encoding in fnname. */ @@ -92,6 +93,9 @@ i386_pe_unique_section (decl, reloc) without a .rdata section. */ if (TREE_CODE (decl) == FUNCTION_DECL) prefix = ".text$"; +/* else if (DECL_INITIAL (decl) == 0 + || DECL_INITIAL (decl) == error_mark_node) + prefix = ".bss"; */ else if (DECL_READONLY_SECTION (decl, reloc)) #ifdef READONLY_DATA_SECTION prefix = ".rdata$"; diff --git a/contrib/gcc/config/i386/isc.h b/contrib/gcc/config/i386/isc.h index 6c1c4c7..eea9811 100644 --- a/contrib/gcc/config/i386/isc.h +++ b/contrib/gcc/config/i386/isc.h @@ -2,7 +2,7 @@ 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. */ +/* 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}}}\ @@ -33,7 +33,7 @@ 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. */ + structures. */ #undef RETURN_POPS_ARGS #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ @@ -56,10 +56,10 @@ 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. */ + So don't make TARGET_IEEE_FP default for ISC. */ -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_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. */ @@ -74,8 +74,8 @@ #undef ASM_FILE_START #define ASM_FILE_START(FILE) \ do { \ - int len = strlen (main_input_filename); \ - char *na = main_input_filename + len; \ + const int len = strlen (main_input_filename); \ + const char *na = main_input_filename + len; \ char shorter[15]; \ /* NA gets MAIN_INPUT_FILENAME sans directory names. */\ while (na > main_input_filename) \ @@ -92,5 +92,5 @@ } while (0) /* Work around assembler forward label references generated in exception - handling code. */ + handling code. */ #define DWARF2_UNWIND_INFO 0 diff --git a/contrib/gcc/config/i386/isccoff.h b/contrib/gcc/config/i386/isccoff.h index 595c7d9..9efd9ad 100644 --- a/contrib/gcc/config/i386/isccoff.h +++ b/contrib/gcc/config/i386/isccoff.h @@ -4,7 +4,7 @@ (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. */ +/* Mostly it's like AT&T Unix System V. */ #include "i386/sysv3.h" diff --git a/contrib/gcc/config/i386/iscdbx.h b/contrib/gcc/config/i386/iscdbx.h index 6c2d42e..6d1f341 100644 --- a/contrib/gcc/config/i386/iscdbx.h +++ b/contrib/gcc/config/i386/iscdbx.h @@ -20,7 +20,7 @@ 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. */ +/* Mostly it's like AT&T Unix System V with dbx-in-coff. */ #include "i386/svr3dbx.h" @@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */ #undef ENDFILE_SPEC #include "i386/isc.h" -/* Overridden defines for ifile usage. */ +/* Overridden defines for ifile usage. */ #undef STARTFILE_SPEC #define STARTFILE_SPEC \ diff --git a/contrib/gcc/config/i386/linux-aout.h b/contrib/gcc/config/i386/linux-aout.h index de81d87..302ee69 100644 --- a/contrib/gcc/config/i386/linux-aout.h +++ b/contrib/gcc/config/i386/linux-aout.h @@ -31,7 +31,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)" +#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}" @@ -69,6 +69,3 @@ Boston, MA 02111-1307, USA. */ #undef LINK_SPEC #define LINK_SPEC "-m i386linux" - -/* Get perform_* macros to build libgcc.a. */ -#include "i386/perform.h" diff --git a/contrib/gcc/config/i386/linux-oldld.h b/contrib/gcc/config/i386/linux-oldld.h index 4e3085b..6102aa8 100644 --- a/contrib/gcc/config/i386/linux-oldld.h +++ b/contrib/gcc/config/i386/linux-oldld.h @@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)" +#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}" @@ -70,6 +70,3 @@ Boston, MA 02111-1307, USA. */ #undef LINK_SPEC #define LINK_SPEC "" - -/* Get perform_* macros to build libgcc.a. */ -#include <i386/perform.h> diff --git a/contrib/gcc/config/i386/linux.h b/contrib/gcc/config/i386/linux.h index 7b368f8..de634d3 100644 --- a/contrib/gcc/config/i386/linux.h +++ b/contrib/gcc/config/i386/linux.h @@ -1,5 +1,6 @@ /* Definitions for Intel 386 running Linux-based GNU systems with ELF format. - Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002 + Free Software Foundation, Inc. Contributed by Eric Youngdale. Modified for stabs-in-ELF by H.J. Lu. @@ -22,12 +23,15 @@ 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 */ +/* 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); \ + if (ix86_asm_dialect == ASM_INTEL) \ + fputs ("\t.intel_syntax\n", FILE); \ + } while (0) #undef TARGET_VERSION #define TARGET_VERSION fprintf (stderr, " (i386 Linux/ELF)"); @@ -40,104 +44,34 @@ Boston, MA 02111-1307, USA. */ #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. */ + (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) + +/* Output assembler code to FILE to call the profiler. + To the best of my knowledge, no Linux libc has required the label + argument to mcount. */ + +#define NO_PROFILE_COUNTERS #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"); \ - } \ + fprintf (FILE, "\tcall\t*mcount@GOT(%%ebx)\n"); \ else \ - { \ - fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \ - fprintf (FILE, "\tcall mcount\n"); \ - } \ + fprintf (FILE, "\tcall\tmcount\n"); \ } +/* True if it is possible to profile code that does not have a frame + pointer. + + The GLIBC version of mcount for the x86 assumes that there is a + frame, so we cannot allow profiling without a frame pointer. */ + +#undef TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER +#define TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER false + #undef SIZE_TYPE #define SIZE_TYPE "unsigned int" @@ -151,7 +85,7 @@ Boston, MA 02111-1307, USA. */ #define WCHAR_TYPE_SIZE BITS_PER_WORD #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__i386__ -Dlinux -Asystem(posix)" +#define CPP_PREDEFINES "-D__ELF__ -Dunix -Dlinux -Asystem=posix" #undef CPP_SPEC #ifdef USE_GNULIBC_1 @@ -177,7 +111,7 @@ Boston, MA 02111-1307, USA. */ 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. */ +/* If ELF is the default format, we should not use /lib/elf. */ #undef LINK_SPEC #ifdef USE_GNULIBC_1 @@ -208,9 +142,6 @@ Boston, MA 02111-1307, USA. */ %{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. @@ -234,3 +165,116 @@ Boston, MA 02111-1307, USA. */ } \ } while (0) #endif + +#if defined(__PIC__) && defined (USE_GNULIBC_1) +/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr, + __environ and atexit. We have to make sure they are in the .dynsym + section. We do this by forcing the assembler to create undefined + references to these symbols in the object file. */ +#undef CRT_CALL_STATIC_FUNCTION +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ + asm (SECTION_OP "\n\t" \ + "call " USER_LABEL_PREFIX #FUNC "\n" \ + TEXT_SECTION_ASM_OP "\n\t" \ + ".extern ___brk_addr\n\t" \ + ".type ___brk_addr,@object\n\t" \ + ".extern __environ\n\t" \ + ".type __environ,@object\n\t" \ + ".extern atexit\n\t" \ + ".type atexit,@function"); +#endif + +/* Handle special EH pointer encodings. Absolute, pc-relative, and + indirect are handled automatically. */ +#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \ + do { \ + if ((SIZE) == 4 && ((ENCODING) & 0x70) == DW_EH_PE_datarel) \ + { \ + fputs (ASM_LONG, FILE); \ + assemble_name (FILE, XSTR (ADDR, 0)); \ + fputs (((ENCODING) & DW_EH_PE_indirect ? "@GOT" : "@GOTOFF"), FILE); \ + goto DONE; \ + } \ + } while (0) + +/* Used by crtstuff.c to initialize the base of data-relative relocations. + These are GOT relative on x86, so return the pic register. */ +#ifdef __PIC__ +#define CRT_GET_RFIB_DATA(BASE) \ + { \ + register void *ebx_ __asm__("ebx"); \ + BASE = ebx_; \ + } +#else +#define CRT_GET_RFIB_DATA(BASE) \ + __asm__ ("call\t.LPR%=\n" \ + ".LPR%=:\n\t" \ + "popl\t%0\n\t" \ + /* Due to a GAS bug, this cannot use EAX. That encodes \ + smaller than the traditional EBX, which results in the \ + offset being off by one. */ \ + "addl\t$_GLOBAL_OFFSET_TABLE_+[.-.LPR%=],%0" \ + : "=d"(BASE)) +#endif + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. */ + +#ifdef IN_LIBGCC2 +#include <signal.h> +#include <sys/ucontext.h> +#endif + +#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \ + do { \ + unsigned char *pc_ = (CONTEXT)->ra; \ + struct sigcontext *sc_; \ + long new_cfa_; \ + \ + /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ \ + if (*(unsigned short *)(pc_+0) == 0xb858 \ + && *(unsigned int *)(pc_+2) == 119 \ + && *(unsigned short *)(pc_+6) == 0x80cd) \ + sc_ = (CONTEXT)->cfa + 4; \ + /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ \ + else if (*(unsigned char *)(pc_+0) == 0xb8 \ + && *(unsigned int *)(pc_+1) == 173 \ + && *(unsigned short *)(pc_+5) == 0x80cd) \ + { \ + struct rt_sigframe { \ + int sig; \ + struct siginfo *pinfo; \ + void *puc; \ + struct siginfo info; \ + struct ucontext uc; \ + } *rt_ = (CONTEXT)->cfa; \ + sc_ = (struct sigcontext *) &rt_->uc.uc_mcontext; \ + } \ + else \ + break; \ + \ + new_cfa_ = sc_->esp; \ + (FS)->cfa_how = CFA_REG_OFFSET; \ + (FS)->cfa_reg = 4; \ + (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa; \ + \ + /* The SVR4 register numbering macros aren't usable in libgcc. */ \ + (FS)->regs.reg[0].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[0].loc.offset = (long)&sc_->eax - new_cfa_; \ + (FS)->regs.reg[3].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[3].loc.offset = (long)&sc_->ebx - new_cfa_; \ + (FS)->regs.reg[1].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[1].loc.offset = (long)&sc_->ecx - new_cfa_; \ + (FS)->regs.reg[2].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[2].loc.offset = (long)&sc_->edx - new_cfa_; \ + (FS)->regs.reg[6].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[6].loc.offset = (long)&sc_->esi - new_cfa_; \ + (FS)->regs.reg[7].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[7].loc.offset = (long)&sc_->edi - new_cfa_; \ + (FS)->regs.reg[5].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[5].loc.offset = (long)&sc_->ebp - new_cfa_; \ + (FS)->regs.reg[8].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[8].loc.offset = (long)&sc_->eip - new_cfa_; \ + (FS)->retaddr_column = 8; \ + goto SUCCESS; \ + } while (0) diff --git a/contrib/gcc/config/i386/linux64.h b/contrib/gcc/config/i386/linux64.h new file mode 100644 index 0000000..8d70972 --- /dev/null +++ b/contrib/gcc/config/i386/linux64.h @@ -0,0 +1,48 @@ +/* Definitions for AMD x86-64 running Linux-based GNU systems with ELF format. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Jan Hubicka <jh@suse.cz>, based on linux.h. + +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 + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (x86-64 Linux/ELF)"); + +#undef CPP_PREDEFINES +#define CPP_PREDEFINES "-D__ELF__ -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} %{pthread:-D_REENTRANT} %{!m32:-D__LONG_MAX__=9223372036854775807L}" + +/* Provide a LINK_SPEC. 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. + + When the -shared link option is used a final link is not being + done. */ + +#undef LINK_SPEC +#define LINK_SPEC "%{!m32:-m elf_x86_64} %{m32:-m elf_i386} %{shared:-shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib64/ld-linux-x86-64.so.2}} \ + %{static:-static}}" + diff --git a/contrib/gcc/config/i386/lynx-ng.h b/contrib/gcc/config/i386/lynx-ng.h index ec4e2961..49150a3 100644 --- a/contrib/gcc/config/i386/lynx-ng.h +++ b/contrib/gcc/config/i386/lynx-ng.h @@ -22,7 +22,8 @@ Boston, MA 02111-1307, USA. */ #include <lynx-ng.h> #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Di386 -DI386 -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-Dunix -DI386 -DLynx -DIBITS32 \ + -Asystem=unix -Asystem=lynx" /* Provide required defaults for linker switches. */ diff --git a/contrib/gcc/config/i386/lynx.h b/contrib/gcc/config/i386/lynx.h index 73111f9..91ed31e 100644 --- a/contrib/gcc/config/i386/lynx.h +++ b/contrib/gcc/config/i386/lynx.h @@ -22,11 +22,11 @@ Boston, MA 02111-1307, USA. */ #include <lynx.h> #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -Di386 -DI386 -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-DI386 -DLynx -DIBITS32 -Asystem=unix -Asystem=lynx" -/* The prefix to add to user-visible assembler symbols. */ +/* The prefix to add to user-visible assembler symbols. */ -/* Override the svr3 convention of adding a leading underscore. */ +/* Override the svr3 convention of adding a leading underscore. */ #undef USER_LABEL_PREFIX #define USER_LABEL_PREFIX "" diff --git a/contrib/gcc/config/i386/mach.h b/contrib/gcc/config/i386/mach.h index 4b7cf37..7e2b1cc 100644 --- a/contrib/gcc/config/i386/mach.h +++ b/contrib/gcc/config/i386/mach.h @@ -6,11 +6,8 @@ #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)" +#define CPP_PREDEFINES "-Dunix -DMACH -Asystem=unix -Asystem=mach" /* Specify extra dir to search for include files. */ #define SYSTEM_INCLUDE_DIR "/usr/mach/include" diff --git a/contrib/gcc/config/i386/mingw32.h b/contrib/gcc/config/i386/mingw32.h index 552cbcd..b93e856 100644 --- a/contrib/gcc/config/i386/mingw32.h +++ b/contrib/gcc/config/i386/mingw32.h @@ -1,8 +1,6 @@ /* 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. + hosting on Windows32, using GNU tools and the Windows32 API Library. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -19,65 +17,81 @@ 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. */ +Boston, MA 02111-1307, USA. */ /* Most of this is the same as for cygwin, except for changing some specs. */ +/* Mingw GCC, unlike Cygwin's, must be relocatable. This macro must + be defined before any other files are included. */ +#ifndef WIN32_NO_ABSOLUTE_INST_DIRS +#define WIN32_NO_ABSOLUTE_INST_DIRS 1 +#endif + #include "i386/cygwin.h" +#define TARGET_EXECUTABLE_SUFFIX ".exe" + /* 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. */ + 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)" +#define CPP_PREDEFINES "-D_WIN32 -D__WIN32 -D__WIN32__ -DWIN32 \ + -D__MINGW32__ -D__MSVCRT__ -DWINNT -D_X86_=1 \ + -Asystem=winnt" /* 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" +#define STANDARD_INCLUDE_DIR "/usr/local/mingw32/include" +#undef STANDARD_INCLUDE_COMPONENT +#define STANDARD_INCLUDE_COMPONENT "MINGW" #undef CPP_SPEC -#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE}" +#define CPP_SPEC \ + "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT} \ + -D__stdcall=__attribute__((__stdcall__)) \ + -D__cdecl=__attribute__((__cdecl__)) \ + %{!ansi:-D_stdcall=__attribute__((__stdcall__)) \ + -D_cdecl=__attribute__((__cdecl__))} \ + -D__declspec(x)=__attribute__((x))" + /* For Windows applications, include more libraries, but always include kernel32. */ #undef LIB_SPEC -#define LIB_SPEC "%{mwindows:-lgdi32 -lcomdlg32} \ +#define LIB_SPEC "%{pg:-lgmon} %{mwindows:-lgdi32 -lcomdlg32} \ -luser32 -lkernel32 -ladvapi32 -lshell32" /* Include in the mingw32 libraries with libgcc */ +#undef LINK_SPEC +#define LINK_SPEC "%{mwindows:--subsystem windows} \ + %{mconsole:--subsystem console} \ + %{shared: %{mdll: %eshared and mdll are not compatible}} \ + %{shared: --shared} %{mdll:--dll} \ + %{static:-Bstatic} %{!static:-Bdynamic} \ + %{shared|mdll: -e _DllMainCRTStartup@12}" + +/* Include in the mingw32 libraries with libgcc */ #undef LIBGCC_SPEC -#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lmsvcrt" +#define LIBGCC_SPEC \ + "%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt" #undef STARTFILE_SPEC -#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s}" +#define STARTFILE_SPEC "%{shared|mdll:dllcrt2%O%s} \ + %{!shared:%{!mdll:crt2%O%s}} %{pg:gcrt2%O%s}" -/* MS runtime does not need a separate math library. */ +/* MS runtime does not need a separate math library. */ +#undef MATH_LIBRARY #define MATH_LIBRARY "" -/* Output STRING, a string representing a filename, to FILE. We canonicalize - it to be in MS-DOS format. */ +/* Output STRING, a string representing a filename, to FILE. + We canonicalize it to be in MS-DOS format. */ +#undef OUTPUT_QUOTED_STRING #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) \ { \ @@ -92,3 +106,7 @@ do { \ putc ('\"', asm_file); \ } while (0) +/* Override Cygwin's definition. This is necessary now due to the way + Cygwin profiling code is written. Once "fixed", we can remove this. */ +#undef SUBTARGET_PROLOGUE + diff --git a/contrib/gcc/config/i386/mmintrin.h b/contrib/gcc/config/i386/mmintrin.h new file mode 100644 index 0000000..41dc4be --- /dev/null +++ b/contrib/gcc/config/i386/mmintrin.h @@ -0,0 +1,542 @@ +/* Copyright (C) 2002 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. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself 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. */ + +/* Implemented from the specification included in the Intel C++ Compiler + User Guide and Reference, version 5.0. */ + +#ifndef _MMINTRIN_H_INCLUDED +#define _MMINTRIN_H_INCLUDED + +/* The data type intended for user use. */ +typedef unsigned long long __m64; + +/* Internal data types for implementing the intrinsics. */ +typedef int __v2si __attribute__ ((__mode__ (__V2SI__))); +typedef int __v4hi __attribute__ ((__mode__ (__V4HI__))); +typedef int __v8qi __attribute__ ((__mode__ (__V8QI__))); + +/* Empty the multimedia state. */ +static __inline void +_mm_empty (void) +{ + __builtin_ia32_emms (); +} + +/* Convert I to a __m64 object. The integer is zero-extended to 64-bits. */ +static __inline __m64 +_mm_cvtsi32_si64 (int __i) +{ + return (unsigned int) __i; +} + +/* Convert the lower 32 bits of the __m64 object into an integer. */ +static __inline int +_mm_cvtsi64_si32 (__m64 __i) +{ + return __i; +} + +/* Pack the four 16-bit values from M1 into the lower four 8-bit values of + the result, and the four 16-bit values from M2 into the upper four 8-bit + values of the result, all with signed saturation. */ +static __inline __m64 +_mm_packs_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_packsswb ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Pack the two 32-bit values from M1 in to the lower two 16-bit values of + the result, and the two 32-bit values from M2 into the upper two 16-bit + values of the result, all with signed saturation. */ +static __inline __m64 +_mm_packs_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_packssdw ((__v2si)__m1, (__v2si)__m2); +} + +/* Pack the four 16-bit values from M1 into the lower four 8-bit values of + the result, and the four 16-bit values from M2 into the upper four 8-bit + values of the result, all with unsigned saturation. */ +static __inline __m64 +_mm_packs_pu16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_packuswb ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Interleave the four 8-bit values from the high half of M1 with the four + 8-bit values from the high half of M2. */ +static __inline __m64 +_mm_unpackhi_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpckhbw ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Interleave the two 16-bit values from the high half of M1 with the two + 16-bit values from the high half of M2. */ +static __inline __m64 +_mm_unpackhi_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpckhwd ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Interleave the 32-bit value from the high half of M1 with the 32-bit + value from the high half of M2. */ +static __inline __m64 +_mm_unpackhi_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpckhdq ((__v2si)__m1, (__v2si)__m2); +} + +/* Interleave the four 8-bit values from the low half of M1 with the four + 8-bit values from the low half of M2. */ +static __inline __m64 +_mm_unpacklo_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpcklbw ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Interleave the two 16-bit values from the low half of M1 with the two + 16-bit values from the low half of M2. */ +static __inline __m64 +_mm_unpacklo_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpcklwd ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Interleave the 32-bit value from the low half of M1 with the 32-bit + value from the low half of M2. */ +static __inline __m64 +_mm_unpacklo_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_punpckldq ((__v2si)__m1, (__v2si)__m2); +} + +/* Add the 8-bit values in M1 to the 8-bit values in M2. */ +static __inline __m64 +_mm_add_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Add the 16-bit values in M1 to the 16-bit values in M2. */ +static __inline __m64 +_mm_add_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Add the 32-bit values in M1 to the 32-bit values in M2. */ +static __inline __m64 +_mm_add_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddd ((__v2si)__m1, (__v2si)__m2); +} + +/* Add the 8-bit values in M1 to the 8-bit values in M2 using signed + saturated arithmetic. */ +static __inline __m64 +_mm_adds_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddsb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Add the 16-bit values in M1 to the 16-bit values in M2 using signed + saturated arithmetic. */ +static __inline __m64 +_mm_adds_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddsw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Add the 8-bit values in M1 to the 8-bit values in M2 using unsigned + saturated arithmetic. */ +static __inline __m64 +_mm_adds_pu8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddusb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Add the 16-bit values in M1 to the 16-bit values in M2 using unsigned + saturated arithmetic. */ +static __inline __m64 +_mm_adds_pu16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_paddusw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Subtract the 8-bit values in M2 from the 8-bit values in M1. */ +static __inline __m64 +_mm_sub_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Subtract the 16-bit values in M2 from the 16-bit values in M1. */ +static __inline __m64 +_mm_sub_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Subtract the 32-bit values in M2 from the 32-bit values in M1. */ +static __inline __m64 +_mm_sub_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubd ((__v2si)__m1, (__v2si)__m2); +} + +/* Subtract the 8-bit values in M2 from the 8-bit values in M1 using signed + saturating arithmetic. */ +static __inline __m64 +_mm_subs_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubsb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Subtract the 16-bit values in M2 from the 16-bit values in M1 using + signed saturating arithmetic. */ +static __inline __m64 +_mm_subs_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubsw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Subtract the 8-bit values in M2 from the 8-bit values in M1 using + unsigned saturating arithmetic. */ +static __inline __m64 +_mm_subs_pu8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubusb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Subtract the 16-bit values in M2 from the 16-bit values in M1 using + unsigned saturating arithmetic. */ +static __inline __m64 +_mm_subs_pu16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_psubusw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Multiply four 16-bit values in M1 by four 16-bit values in M2 producing + four 32-bit intermediate results, which are then summed by pairs to + produce two 32-bit results. */ +static __inline __m64 +_mm_madd_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pmaddwd ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Multiply four signed 16-bit values in M1 by four signed 16-bit values in + M2 and produce the high 16 bits of the 32-bit results. */ +static __inline __m64 +_mm_mulhi_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pmulhw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Multiply four 16-bit values in M1 by four 16-bit values in M2 and produce + the low 16 bits of the results. */ +static __inline __m64 +_mm_mullo_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pmullw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Shift four 16-bit values in M left by COUNT. */ +static __inline __m64 +_mm_sll_pi16 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psllw ((__v4hi)__m, __count); +} + +static __inline __m64 +_mm_slli_pi16 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psllw ((__v4hi)__m, __count); +} + +/* Shift two 32-bit values in M left by COUNT. */ +static __inline __m64 +_mm_sll_pi32 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_pslld ((__v2si)__m, __count); +} + +static __inline __m64 +_mm_slli_pi32 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_pslld ((__v2si)__m, __count); +} + +/* Shift the 64-bit value in M left by COUNT. */ +static __inline __m64 +_mm_sll_pi64 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psllq (__m, __count); +} + +static __inline __m64 +_mm_slli_pi64 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psllq (__m, __count); +} + +/* Shift four 16-bit values in M right by COUNT; shift in the sign bit. */ +static __inline __m64 +_mm_sra_pi16 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psraw ((__v4hi)__m, __count); +} + +static __inline __m64 +_mm_srai_pi16 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psraw ((__v4hi)__m, __count); +} + +/* Shift two 32-bit values in M right by COUNT; shift in the sign bit. */ +static __inline __m64 +_mm_sra_pi32 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psrad ((__v2si)__m, __count); +} + +static __inline __m64 +_mm_srai_pi32 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psrad ((__v2si)__m, __count); +} + +/* Shift four 16-bit values in M right by COUNT; shift in zeros. */ +static __inline __m64 +_mm_srl_pi16 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psrlw ((__v4hi)__m, __count); +} + +static __inline __m64 +_mm_srli_pi16 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psrlw ((__v4hi)__m, __count); +} + +/* Shift two 32-bit values in M right by COUNT; shift in zeros. */ +static __inline __m64 +_mm_srl_pi32 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psrld ((__v2si)__m, __count); +} + +static __inline __m64 +_mm_srli_pi32 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psrld ((__v2si)__m, __count); +} + +/* Shift the 64-bit value in M left by COUNT; shift in zeros. */ +static __inline __m64 +_mm_srl_pi64 (__m64 __m, __m64 __count) +{ + return (__m64) __builtin_ia32_psrlq (__m, __count); +} + +static __inline __m64 +_mm_srli_pi64 (__m64 __m, int __count) +{ + return (__m64) __builtin_ia32_psrlq (__m, __count); +} + +/* Bit-wise AND the 64-bit values in M1 and M2. */ +static __inline __m64 +_mm_and_si64 (__m64 __m1, __m64 __m2) +{ + return __builtin_ia32_pand (__m1, __m2); +} + +/* Bit-wise complement the 64-bit value in M1 and bit-wise AND it with the + 64-bit value in M2. */ +static __inline __m64 +_mm_andnot_si64 (__m64 __m1, __m64 __m2) +{ + return __builtin_ia32_pandn (__m1, __m2); +} + +/* Bit-wise inclusive OR the 64-bit values in M1 and M2. */ +static __inline __m64 +_mm_or_si64 (__m64 __m1, __m64 __m2) +{ + return __builtin_ia32_por (__m1, __m2); +} + +/* Bit-wise exclusive OR the 64-bit values in M1 and M2. */ +static __inline __m64 +_mm_xor_si64 (__m64 __m1, __m64 __m2) +{ + return __builtin_ia32_pxor (__m1, __m2); +} + +/* Compare eight 8-bit values. The result of the comparison is 0xFF if the + test is true and zero if false. */ +static __inline __m64 +_mm_cmpeq_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpeqb ((__v8qi)__m1, (__v8qi)__m2); +} + +static __inline __m64 +_mm_cmpgt_pi8 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpgtb ((__v8qi)__m1, (__v8qi)__m2); +} + +/* Compare four 16-bit values. The result of the comparison is 0xFFFF if + the test is true and zero if false. */ +static __inline __m64 +_mm_cmpeq_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpeqw ((__v4hi)__m1, (__v4hi)__m2); +} + +static __inline __m64 +_mm_cmpgt_pi16 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpgtw ((__v4hi)__m1, (__v4hi)__m2); +} + +/* Compare two 32-bit values. The result of the comparison is 0xFFFFFFFF if + the test is true and zero if false. */ +static __inline __m64 +_mm_cmpeq_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpeqd ((__v2si)__m1, (__v2si)__m2); +} + +static __inline __m64 +_mm_cmpgt_pi32 (__m64 __m1, __m64 __m2) +{ + return (__m64) __builtin_ia32_pcmpgtd ((__v2si)__m1, (__v2si)__m2); +} + +/* Creates a 64-bit zero. */ +static __inline __m64 +_mm_setzero_si64 (void) +{ + return __builtin_ia32_mmx_zero (); +} + +/* Creates a vector of two 32-bit values; I0 is least significant. */ +static __inline __m64 +_mm_set_pi32 (int __i1, int __i0) +{ + union { + __m64 __q; + struct { + unsigned int __i0; + unsigned int __i1; + } __s; + } __u; + + __u.__s.__i0 = __i0; + __u.__s.__i1 = __i1; + + return __u.__q; +} + +/* Creates a vector of four 16-bit values; W0 is least significant. */ +static __inline __m64 +_mm_set_pi16 (short __w3, short __w2, short __w1, short __w0) +{ + unsigned int __i1 = (unsigned short)__w3 << 16 | (unsigned short)__w2; + unsigned int __i0 = (unsigned short)__w1 << 16 | (unsigned short)__w0; + return _mm_set_pi32 (__i1, __i0); + +} + +/* Creates a vector of eight 8-bit values; B0 is least significant. */ +static __inline __m64 +_mm_set_pi8 (char __b7, char __b6, char __b5, char __b4, + char __b3, char __b2, char __b1, char __b0) +{ + unsigned int __i1, __i0; + + __i1 = (unsigned char)__b7; + __i1 = __i1 << 8 | (unsigned char)__b6; + __i1 = __i1 << 8 | (unsigned char)__b5; + __i1 = __i1 << 8 | (unsigned char)__b4; + + __i0 = (unsigned char)__b3; + __i0 = __i0 << 8 | (unsigned char)__b2; + __i0 = __i0 << 8 | (unsigned char)__b1; + __i0 = __i0 << 8 | (unsigned char)__b0; + + return _mm_set_pi32 (__i1, __i0); +} + +/* Similar, but with the arguments in reverse order. */ +static __inline __m64 +_mm_setr_pi32 (int __i0, int __i1) +{ + return _mm_set_pi32 (__i1, __i0); +} + +static __inline __m64 +_mm_setr_pi16 (short __w0, short __w1, short __w2, short __w3) +{ + return _mm_set_pi16 (__w3, __w2, __w1, __w0); +} + +static __inline __m64 +_mm_setr_pi8 (char __b0, char __b1, char __b2, char __b3, + char __b4, char __b5, char __b6, char __b7) +{ + return _mm_set_pi8 (__b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0); +} + +/* Creates a vector of two 32-bit values, both elements containing I. */ +static __inline __m64 +_mm_set1_pi32 (int __i) +{ + return _mm_set_pi32 (__i, __i); +} + +/* Creates a vector of four 16-bit values, all elements containing W. */ +static __inline __m64 +_mm_set1_pi16 (short __w) +{ + unsigned int __i = (unsigned short)__w << 16 | (unsigned short)__w; + return _mm_set1_pi32 (__i); +} + +/* Creates a vector of four 16-bit values, all elements containing B. */ +static __inline __m64 +_mm_set1_pi8 (char __b) +{ + unsigned int __w = (unsigned char)__b << 8 | (unsigned char)__b; + unsigned int __i = __w << 16 | __w; + return _mm_set1_pi32 (__i); +} + +#endif /* _MMINTRIN_H_INCLUDED */ diff --git a/contrib/gcc/config/i386/moss.h b/contrib/gcc/config/i386/moss.h index d2548e3..200cae0 100644 --- a/contrib/gcc/config/i386/moss.h +++ b/contrib/gcc/config/i386/moss.h @@ -1,5 +1,5 @@ /* Definitions for Intel 386 running MOSS - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 2001 Free Software Foundation, Inc. Contributed by Bryan Ford <baford@cs.utah.edu> This file is part of GNU CC. @@ -19,11 +19,8 @@ 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)" +#define CPP_PREDEFINES "-D__ELF__ -Dmoss -Asystem=posix" #undef STARTFILE_SPEC #define STARTFILE_SPEC "crt0.o%s" diff --git a/contrib/gcc/config/i386/netbsd-elf.h b/contrib/gcc/config/i386/netbsd-elf.h new file mode 100644 index 0000000..7ff3c21 --- /dev/null +++ b/contrib/gcc/config/i386/netbsd-elf.h @@ -0,0 +1,130 @@ +/* Definitions of target machine for GNU compiler, + for i386/ELF NetBSD systems. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Contributed by matthew green <mrg@eterna.com.au> + +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. */ + +/* Provide a LINK_SPEC appropriate for a NetBSD/i386 ELF target. + This is a copy of LINK_SPEC from <netbsd-elf.h> tweaked for + the i386 target. */ + +#undef LINK_SPEC +#define LINK_SPEC \ + "%{assert*} %{R*} \ + %{shared:-shared} \ + %{!shared: \ + -dc -dp \ + %{!nostdlib: \ + %{!r*: \ + %{!e*:-e __start}}} \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /usr/libexec/ld.elf_so}} \ + %{static:-static}}" + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES \ + "-D__NetBSD__ -D__ELF__ -Asystem=unix -Asystem=NetBSD" + +/* Make gcc agree with <machine/ansi.h> */ + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_UNSIGNED +#define WCHAR_UNSIGNED 0 + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +#undef WINT_TYPE +#define WINT_TYPE "int" + +#undef ASM_APP_ON +#define ASM_APP_ON "#APP\n" + +#undef ASM_APP_OFF +#define ASM_APP_OFF "#NO_APP\n" + +#undef ASM_FINAL_SPEC + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) svr4_dbx_register_map[n] + + +/* Output assembler code to FILE to call the profiler. */ + +#undef NO_PROFILE_COUNTERS +#define NO_PROFILE_COUNTERS + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (flag_pic) \ + fprintf (FILE, "\tcall __mcount@PLT\n"); \ + else \ + fprintf (FILE, "\tcall __mcount\n"); \ +} + + +#undef HAS_INIT_SECTION + +/* This is how we tell the assembler that two symbols have the same value. */ + +#define ASM_OUTPUT_DEF(FILE,NAME1,NAME2) \ + do { assemble_name(FILE, NAME1); \ + fputs(" = ", FILE); \ + assemble_name(FILE, NAME2); \ + fputc('\n', FILE); } while (0) + +/* 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 + +/* We always use gas here, so we don't worry about ECOFF assembler + problems. */ +#undef TARGET_GAS +#define TARGET_GAS 1 + +/* Default to pcc-struct-return, because this is the ELF abi and + we don't care about compatibility with older gcc versions. */ +#define DEFAULT_PCC_STRUCT_RETURN 1 + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (NetBSD/i386 ELF)"); diff --git a/contrib/gcc/config/i386/netbsd.h b/contrib/gcc/config/i386/netbsd.h index d9f0646..659a4f0 100644 --- a/contrib/gcc/config/i386/netbsd.h +++ b/contrib/gcc/config/i386/netbsd.h @@ -3,19 +3,18 @@ #include <i386/gstabs.h> -/* Get perform_* macros to build libgcc.a. */ -#include <i386/perform.h> - /* Get generic NetBSD definitions. */ #include <netbsd.h> +#include <netbsd-aout.h> /* This goes away when the math-emulator is fixed */ -#undef TARGET_DEFAULT -#define TARGET_DEFAULT \ +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_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)" +#define CPP_PREDEFINES "-Dunix -D__NetBSD__ \ + -Asystem=unix -Asystem=bsd -Asystem=NetBSD" #undef SIZE_TYPE #define SIZE_TYPE "unsigned int" @@ -37,22 +36,6 @@ #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. */ @@ -84,4 +67,3 @@ /* Until they use ELF or something that handles dwarf2 unwinds and initialization stuff better. */ #define DWARF2_UNWIND_INFO 0 - diff --git a/contrib/gcc/config/i386/netbsd64.h b/contrib/gcc/config/i386/netbsd64.h new file mode 100644 index 0000000..74862af --- /dev/null +++ b/contrib/gcc/config/i386/netbsd64.h @@ -0,0 +1,66 @@ +/* Definitions of target machine for GNU compiler, + for x86-64/ELF NetBSD systems. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Wasabi Systems, 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. */ + + +/* Provide a LINK_SPEC appropriate for a NetBSD/x86-64 ELF target. + This is a copy of LINK_SPEC from <netbsd-elf.h> tweaked for + the x86-64 target. */ + +#undef LINK_SPEC +#define LINK_SPEC \ + "%{!m32:-m elf_x86_64} \ + %{m32:-m elf_i386} \ + %{assert*} %{R*} \ + %{shared:-shared} \ + %{!shared: \ + -dc -dp \ + %{!nostdlib: \ + %{!r*: \ + %{!e*:-e _start}}} \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /usr/libexec/ld.elf_so}} \ + %{static:-static}}" + + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES \ + "-D__NetBSD__ -D__ELF__ -Asystem=unix -Asystem=NetBSD" + + +/* Output assembler code to FILE to call the profiler. */ + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (TARGET_64BIT && flag_pic) \ + fprintf (FILE, "\tcall *__mcount@PLT\n"); \ + else if (flag_pic) \ + fprintf (FILE, "\tcall *__mcount@PLT\n"); \ + else \ + fprintf (FILE, "\tcall __mcount\n"); \ +} + + +#undef TARGET_VERSION +#define TARGET_VERSION fprintf (stderr, " (NetBSD/x86_64 ELF)"); diff --git a/contrib/gcc/config/i386/next.h b/contrib/gcc/config/i386/next.h index bbc0e6b..3081fde 100644 --- a/contrib/gcc/config/i386/next.h +++ b/contrib/gcc/config/i386/next.h @@ -23,8 +23,8 @@ Boston, MA 02111-1307, USA. */ /* By default, target has a 80387, with IEEE FP. */ -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP) +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP) /* Implicit library calls should use memcpy, not bcopy, etc. */ @@ -42,54 +42,6 @@ Boston, MA 02111-1307, USA. */ ((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 @@ -122,20 +74,21 @@ Boston, MA 02111-1307, USA. */ count is in %cl. Some assemblers require %cl as an argument; some don't. - GAS requires the %cl argument, so override unx386.h. */ + 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. */ +/* 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)" +#define CPP_PREDEFINES "-DNeXT -Dunix -D__MACH__ -D__LITTLE_ENDIAN__ \ + -D__ARCHITECTURE__=\"i386\" -Asystem=unix -Asystem=mach" -/* This accounts for the return pc and saved fp on the 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 @@ -147,7 +100,7 @@ Boston, MA 02111-1307, USA. */ #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*%s%ld", (PREFIX), (long)(NUMBER)) #undef ASM_OUTPUT_INTERNAL_LABEL #define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ diff --git a/contrib/gcc/config/i386/openbsd.h b/contrib/gcc/config/i386/openbsd.h index dc84f89..a07ee15 100644 --- a/contrib/gcc/config/i386/openbsd.h +++ b/contrib/gcc/config/i386/openbsd.h @@ -1,6 +1,5 @@ /* Configuration for an OpenBSD i386 target. - - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -24,20 +23,18 @@ Boston, MA 02111-1307, USA. */ #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 \ +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_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)" +#define CPP_PREDEFINES "-D__unix__ -D__OpenBSD__ \ + -Asystem=unix -Asystem=bsd -Asystem=OpenBSD" /* Layout of source language data types. */ @@ -62,24 +59,6 @@ Boston, MA 02111-1307, USA. */ #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 @@ -114,6 +93,8 @@ Boston, MA 02111-1307, USA. */ configuration files... */ #define DWARF2_UNWIND_INFO 0 +#undef ASM_PREFERRED_EH_DATA_FORMAT + /* Assembler format: alignment output. */ /* A C statement to output to the stdio stream FILE an assembler @@ -134,3 +115,6 @@ Boston, MA 02111-1307, USA. */ /* Note that we pick up ASM_OUTPUT_MI_THUNK from unix.h. */ +#undef ASM_COMMENT_START +#define ASM_COMMENT_START ";#" + diff --git a/contrib/gcc/config/i386/osf1elf.h b/contrib/gcc/config/i386/osf1elf.h index 003400b..812e991 100644 --- a/contrib/gcc/config/i386/osf1elf.h +++ b/contrib/gcc/config/i386/osf1elf.h @@ -1,14 +1,14 @@ /* OSF/1 1.3 now is compitable with SVR4, so include sysv4.h, and - put difference here. */ + put difference here. + Copyright (C) 2000 Free Software Foundation, Inc. */ #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)"); +#define TARGET_OSF1ELF + /* WORD_SWITCH_TAKES_ARG defined in svr4 is not correct. We also need an extra -soname */ #undef WORD_SWITCH_TAKES_ARG @@ -20,6 +20,7 @@ extern char *sys_siglist[]; /* Note, -fpic and -fPIC are equivalent */ #undef CPP_SPEC #define CPP_SPEC "\ +%(cpp_cpu) \ %{fpic: -D__SHARED__} %{fPIC: %{!fpic: -D__SHARED__}} \ %{.S: %{!ansi:%{!traditional:%{!traditional-cpp:%{!ftraditional: -traditional}}}}} \ %{.S: -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \ @@ -31,7 +32,7 @@ extern char *sys_siglist[]; /* -mmcount or -mno-mcount should be used with -pg or -p */ #undef CC1_SPEC -#define CC1_SPEC "%{p: %{!mmcount: %{!mno-mcount: -mno-mcount }}} \ +#define CC1_SPEC "%(cc1_cpu) %{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 @@ -39,7 +40,8 @@ extern char *sys_siglist[]; */ #undef CPP_PREDEFINES #define CPP_PREDEFINES \ - "-D__NO_UNDERSCORES__ -D__ELF__ -DOSF -DOSF1 -Di386 -Dunix -Asystem(xpg4) -Asystem(osf1) -Acpu(i386) -Amachine(i386)" + "-D__NO_UNDERSCORES__ -D__ELF__ -DOSF -DOSF1 -Dunix \ + -Asystem=unix -Asystem=xpg4 -Asystem=osf1" /* current OSF/1 doesn't provide separate crti.o and gcrti.o (and also, crtn.o and gcrtn.o) for profile. */ @@ -84,21 +86,6 @@ extern char *sys_siglist[]; #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 @@ -121,7 +108,8 @@ extern char *sys_siglist[]; #undef SUBTARGET_SWITCHES #define SUBTARGET_SWITCHES \ - { "mcount", -MASK_NO_MCOUNT, "Profiling uses mcount" }, \ + { "mcount", -MASK_NO_MCOUNT, \ + N_("Profiling uses mcount") }, \ { "no-mcount", MASK_NO_MCOUNT, "" }, /* This macro generates the assembly code for function entry. @@ -146,41 +134,6 @@ extern char *sys_siglist[]; #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 @@ -192,7 +145,7 @@ while (0) 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. */ + compiler and look at the assembler code that results. */ #undef FUNCTION_PROFILER #define FUNCTION_PROFILER(FILE, LABELNO) \ @@ -200,9 +153,9 @@ do \ { \ if (!OSF_PROFILE_BEFORE_PROLOGUE) \ { \ - char *prefix = ""; \ - char *lprefix = LPREFIX; \ - int labelno = LABELNO; \ + const char *const prefix = ""; \ + const char *const 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 \ diff --git a/contrib/gcc/config/i386/osf1elfgdb.h b/contrib/gcc/config/i386/osf1elfgdb.h index af6efa2..4071c66 100644 --- a/contrib/gcc/config/i386/osf1elfgdb.h +++ b/contrib/gcc/config/i386/osf1elfgdb.h @@ -2,6 +2,6 @@ with gas and gdb. */ /* Use stabs instead of DWARF debug format. */ +#undef PREFERRED_DEBUGGING_TYPE #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG -#include "i386/osf1elf.h" diff --git a/contrib/gcc/config/i386/osfelf.h b/contrib/gcc/config/i386/osfelf.h index 381ffc2..9b0e633 100644 --- a/contrib/gcc/config/i386/osfelf.h +++ b/contrib/gcc/config/i386/osfelf.h @@ -22,7 +22,7 @@ Boston, MA 02111-1307, USA. */ #include "config/i386/osfrose.h" #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)" +#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem=xpg4" #undef CPP_SPEC #define CPP_SPEC "%(cpp_cpu) \ @@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */ /* Turn on -pic-extern by default for OSF/rose, -fpic for ELF. */ #undef CC1_SPEC -#define CC1_SPEC "\ +#define CC1_SPEC "%(cc1_cpu) \ %{gline:%{!g:%{!g0:%{!g1:%{!g2: -g1}}}}} \ %{!melf: %{!mrose: -melf }} \ %{!mrose: %{!munderscores: %{!mno-underscores: -mno-underscores }} \ diff --git a/contrib/gcc/config/i386/osfrose.h b/contrib/gcc/config/i386/osfrose.h index 9ad9f95..36d6345 100644 --- a/contrib/gcc/config/i386/osfrose.h +++ b/contrib/gcc/config/i386/osfrose.h @@ -1,6 +1,7 @@ /* 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. + Copyright (C) 1991, 1992, 1993, 1996, 1998, 1999, 2000 + Free Software Foundation, Inc. This file is part of GNU CC. @@ -22,9 +23,6 @@ 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 @@ -58,18 +56,27 @@ Boston, MA 02111-1307, USA. */ #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" }, \ + { "half-pic", MASK_HALF_PIC, \ + N_("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, \ + N_("Emit ELF object code") }, \ + { "rose", -MASK_ELF, \ + N_("Emit ROSE object code") }, \ + { "underscores", -MASK_NO_UNDERSCORES, \ + N_("Symbols have a leading underscore") }, \ + { "no-underscores", MASK_NO_UNDERSCORES, "" }, \ + { "large-align", MASK_LARGE_ALIGN, \ + N_("Align to >word boundaries") }, \ + { "no-large-align", -MASK_LARGE_ALIGN, "" }, \ + { "mcount", -MASK_NO_MCOUNT, \ + N_("Use mcount for profiling") }, \ + { "mcount-ptr", MASK_NO_MCOUNT, \ + N_("Use mcount_ptr for profiling") }, \ { "no-mcount", MASK_NO_MCOUNT, "" }, /* OSF/rose uses stabs, not dwarf. */ @@ -86,7 +93,7 @@ Boston, MA 02111-1307, USA. */ /* Change default predefines. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)" +#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem=xpg4" #undef CPP_SPEC #define CPP_SPEC "%(cpp_cpu) \ @@ -104,7 +111,7 @@ Boston, MA 02111-1307, USA. */ /* Turn on -pic-extern by default for OSF/rose, -fpic for ELF. */ #undef CC1_SPEC -#define CC1_SPEC "\ +#define CC1_SPEC "%(cc1_cpu) \ %{gline:%{!g:%{!g0:%{!g1:%{!g2: -g1}}}}} \ %{!melf: %{!mrose: -mrose }} \ %{melf: %{!munderscores: %{!mno-underscores: -mno-underscores }} \ @@ -169,25 +176,13 @@ Boston, MA 02111-1307, USA. */ /* 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" {...}'. */ + 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 \ @@ -196,56 +191,6 @@ Boston, MA 02111-1307, USA. */ || (!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' @@ -256,7 +201,7 @@ while (0) 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. */ + compiler and look at the assembler code that results. */ #undef FUNCTION_PROFILER #define FUNCTION_PROFILER(FILE, LABELNO) \ @@ -264,8 +209,8 @@ do \ { \ if (!OSF_PROFILE_BEFORE_PROLOGUE) \ { \ - char *prefix = (TARGET_UNDERSCORES) ? "_" : ""; \ - char *lprefix = LPREFIX; \ + const char *const prefix = (TARGET_UNDERSCORES) ? "_" : ""; \ + const char *const lprefix = LPREFIX; \ int labelno = LABELNO; \ \ /* Note that OSF/rose blew it in terms of calling mcount, \ @@ -290,7 +235,7 @@ do \ rtx symdef; \ \ HALF_PIC_EXTERNAL ("mcount"); \ - symdef = HALF_PIC_PTR (gen_rtx (SYMBOL_REF, Pmode, "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)); \ } \ @@ -349,8 +294,8 @@ while (0) #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*%s%s%d", (TARGET_UNDERSCORES) ? "" : ".", \ - (PREFIX), (NUMBER)) + sprintf ((BUF), "*%s%s%ld", (TARGET_UNDERSCORES) ? "" : ".", \ + (PREFIX), (long)(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. */ @@ -360,7 +305,7 @@ while (0) fprintf (FILE, "%s%s%d:\n", (TARGET_UNDERSCORES) ? "" : ".", \ PREFIX, NUM) -/* The prefix to add to user-visible assembler symbols. */ +/* The prefix to add to user-visible assembler symbols. */ /* target_flags is not accessible by the preprocessor */ #undef USER_LABEL_PREFIX @@ -374,7 +319,7 @@ 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. */ + 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) \ @@ -384,7 +329,7 @@ while (0) #define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ do \ { \ - fprintf ((FILE), "\t%s\t", SET_ASM_OP); \ + fprintf ((FILE), "%s", SET_ASM_OP); \ assemble_name (FILE, LABEL1); \ fprintf (FILE, ","); \ assemble_name (FILE, LABEL2); \ @@ -501,7 +446,7 @@ while (0) You can also check the information stored in the `symbol_ref' in the definition of `GO_IF_LEGITIMATE_ADDRESS' or - `PRINT_OPERAND_ADDRESS'. */ + `PRINT_OPERAND_ADDRESS'. */ #undef ENCODE_SECTION_INFO #define ENCODE_SECTION_INFO(DECL) \ @@ -561,7 +506,7 @@ while (0) and select that section. */ #undef SELECT_RTX_SECTION -#define SELECT_RTX_SECTION(MODE, RTX) \ +#define SELECT_RTX_SECTION(MODE, RTX, ALIGN) \ do \ { \ if (MODE == Pmode && HALF_PIC_P () && HALF_PIC_ADDRESS_P (RTX)) \ @@ -572,7 +517,7 @@ do \ while (0) #undef SELECT_SECTION -#define SELECT_SECTION(DECL, RELOC) \ +#define SELECT_SECTION(DECL, RELOC, ALIGN) \ { \ if (RELOC && HALF_PIC_P ()) \ data_section (); \ @@ -605,9 +550,9 @@ while (0) 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" +#define TYPE_ASM_OP "\t.type\t" +#define SIZE_ASM_OP "\t.size\t" +#define SET_ASM_OP "\t.set\t" /* This is how we tell the assembler that a symbol is weak. */ @@ -641,7 +586,7 @@ do \ HALF_PIC_DECLARE (NAME); \ if (TARGET_ELF) \ { \ - fprintf (STREAM, "\t%s\t ", TYPE_ASM_OP); \ + fprintf (STREAM, "%s", TYPE_ASM_OP); \ assemble_name (STREAM, NAME); \ putc (',', STREAM); \ fprintf (STREAM, TYPE_OPERAND_FMT, "object"); \ @@ -650,7 +595,7 @@ do \ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ { \ size_directive_output = 1; \ - fprintf (STREAM, "\t%s\t ", SIZE_ASM_OP); \ + fprintf (STREAM, "%s", SIZE_ASM_OP); \ assemble_name (STREAM, NAME); \ fprintf (STREAM, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ } \ @@ -666,20 +611,20 @@ while (0) #define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ do { \ - char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + const 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); \ + fprintf (FILE, "%s", 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. */ +/* This is how to declare a function name. */ #undef ASM_DECLARE_FUNCTION_NAME #define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \ @@ -689,7 +634,7 @@ do \ HALF_PIC_DECLARE (NAME); \ if (TARGET_ELF) \ { \ - fprintf (STREAM, "\t%s\t ", TYPE_ASM_OP); \ + fprintf (STREAM, "%s", TYPE_ASM_OP); \ assemble_name (STREAM, NAME); \ putc (',', STREAM); \ fprintf (STREAM, TYPE_OPERAND_FMT, "function"); \ @@ -719,7 +664,7 @@ do \ labelno++; \ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, (FNAME)); \ fprintf (FILE, ","); \ assemble_name (FILE, label); \ @@ -730,116 +675,20 @@ do \ } \ 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" +#define IDENT_ASM_OP "\t.ident\t" /* Allow #sccs in preprocessor. */ #define SCCS_DIRECTIVE /* This says what to print at the end of the assembly file */ +#undef ASM_FILE_END #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"); \ - } \ + ix86_asm_file_end (STREAM); \ } \ while (0) @@ -850,65 +699,22 @@ while (0) #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. */ +/* 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) +/* Map i386 registers to the numbers dwarf expects. Of course this is + different from what stabs expects. */ #undef DBX_REGISTER_NUMBER -#define DBX_REGISTER_NUMBER(n) ((write_symbols == DWARF_DEBUG) \ - ? DWARF_DBX_REGISTER_NUMBER(n) \ - : STABS_DBX_REGISTER_NUMBER(n)) +#define DBX_REGISTER_NUMBER(n) ((write_symbols == DWARF_DEBUG) \ + ? svr4_dbx_register_map[n] \ + : dbx_register_map[n]) diff --git a/contrib/gcc/config/i386/ptx4-i.h b/contrib/gcc/config/i386/ptx4-i.h index 1537b4a..0c51703 100644 --- a/contrib/gcc/config/i386/ptx4-i.h +++ b/contrib/gcc/config/i386/ptx4-i.h @@ -22,9 +22,6 @@ 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)"); @@ -34,155 +31,17 @@ Boston, MA 02111-1307, USA. */ #undef RETURN_IN_MEMORY #define RETURN_IN_MEMORY(TYPE) \ - (TYPE_MODE (TYPE) == BLKmode) + (TYPE_MODE (TYPE) == BLKmode \ + || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8)) /* 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) -*/ + "-Dunix -D_SEQUENT_ -Asystem=unix -Asystem=ptx4" #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)) +#define DBX_REGISTER_NUMBER(n) svr4_dbx_register_map[n] /* 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 @@ -195,12 +54,13 @@ do { long value[3]; \ #define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ do \ { \ - register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ - register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register const unsigned char *_ascii_bytes = \ + (const unsigned char *) (STR); \ + register const unsigned char *limit = _ascii_bytes + (LENGTH); \ register unsigned bytes_in_chunk = 0; \ for (; _ascii_bytes < limit; _ascii_bytes++) \ { \ - register unsigned char *p; \ + register const unsigned char *p; \ if (bytes_in_chunk >= 64) \ { \ fputc ('\n', (FILE)); \ @@ -208,7 +68,7 @@ do { long value[3]; \ } \ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ continue; \ - if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + if (p < limit && (p - _ascii_bytes) <= (long) STRING_LIMIT) \ { \ if (bytes_in_chunk > 0) \ { \ @@ -232,16 +92,3 @@ do { long value[3]; \ 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/contrib/gcc/config/i386/rtems.h b/contrib/gcc/config/i386/rtems.h index 60e6dc7..9101332 100644 --- a/contrib/gcc/config/i386/rtems.h +++ b/contrib/gcc/config/i386/rtems.h @@ -1,5 +1,5 @@ /* Definitions for rtems targeting an Intel i386 using coff. - Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc. Contributed by Joel Sherrill (joel@OARcorp.com). This file is part of GNU CC. @@ -24,11 +24,14 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Di386 -Drtems -D__rtems__ \ - -Asystem(rtems) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-Drtems -D__rtems__ -Asystem=rtems" /* Generate calls to memcpy, memcmp and memset. */ #ifndef TARGET_MEM_FUNCTIONS #define TARGET_MEM_FUNCTIONS #endif +/* Get machine-independent configuration parameters for RTEMS. */ +#include <rtems.h> + +/* end of i386/rtems.h */ diff --git a/contrib/gcc/config/i386/rtemself.h b/contrib/gcc/config/i386/rtemself.h index d9d9733..6e31f56 100644 --- a/contrib/gcc/config/i386/rtemself.h +++ b/contrib/gcc/config/i386/rtemself.h @@ -1,5 +1,6 @@ /* Definitions for Intel 386 running Linux-based GNU systems with ELF format. - Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000 + Free Software Foundation, Inc. Contributed by Eric Youngdale. Modified for stabs-in-ELF by H.J. Lu. @@ -22,13 +23,6 @@ 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)"); @@ -37,84 +31,8 @@ Boston, MA 02111-1307, USA. */ #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)) +#define DBX_REGISTER_NUMBER(n) svr4_dbx_register_map[n] /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ @@ -148,11 +66,7 @@ Boston, MA 02111-1307, USA. */ #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" +#define CPP_PREDEFINES "-Drtems -D__rtems__ -Asystem=rtems" /* A C statement (sans semicolon) to output to the stdio stream FILE the assembler definition of uninitialized global DECL named @@ -163,7 +77,9 @@ Boston, MA 02111-1307, USA. */ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) #undef STARTFILE_SPEC -#define STARTFILE_SPEC "crt0.o%s" +#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s" #undef ENDFILE_SPEC - +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +/* end of i386/rtemself.h */ diff --git a/contrib/gcc/config/i386/sco5.h b/contrib/gcc/config/i386/sco5.h index ac4e7e1..211ca36 100644 --- a/contrib/gcc/config/i386/sco5.h +++ b/contrib/gcc/config/i386/sco5.h @@ -1,5 +1,6 @@ /* Definitions for Intel 386 running SCO Unix System V 3.2 Version 5. - Copyright (C) 1992, 95-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999, 2000 + Free Software Foundation, Inc. Contributed by Kean Johnston (hug@netcom.com) This file is part of GNU CC. @@ -29,58 +30,51 @@ Boston, MA 02111-1307, USA. */ #define LPREFIX ".L" #undef ALIGN_ASM_OP -#define ALIGN_ASM_OP "\t.align" +#define ALIGN_ASM_OP "\t.align\t" #undef ASCII_DATA_ASM_OP -#define ASCII_DATA_ASM_OP "\t.ascii" - -#undef ASM_BYTE_OP -#define ASM_BYTE_OP "\t.byte" +#define ASCII_DATA_ASM_OP "\t.ascii\t" #undef IDENT_ASM_OP -#define IDENT_ASM_OP "\t.ident" +#define IDENT_ASM_OP "\t.ident\t" #undef COMMON_ASM_OP -#define COMMON_ASM_OP "\t.comm" +#define COMMON_ASM_OP "\t.comm\t" #undef SET_ASM_OP -#define SET_ASM_OP "\t.set" +#define SET_ASM_OP "\t.set\t" #undef LOCAL_ASM_OP -#define LOCAL_ASM_OP "\t.local" - -#undef INT_ASM_OP -#define INT_ASM_OP "\t.long" +#define LOCAL_ASM_OP "\t.local\t" #undef ASM_SHORT -#define ASM_SHORT "\t.value" +#define ASM_SHORT "\t.value\t" #undef ASM_LONG -#define ASM_LONG "\t.long" +#define ASM_LONG "\t.long\t" -#undef ASM_DOUBLE -#define ASM_DOUBLE "\t.double" +#undef ASM_QUAD #undef TYPE_ASM_OP -#define TYPE_ASM_OP "\t.type" +#define TYPE_ASM_OP "\t.type\t" #undef SIZE_ASM_OP -#define SIZE_ASM_OP "\t.size" +#define SIZE_ASM_OP "\t.size\t" #undef STRING_ASM_OP -#define STRING_ASM_OP "\t.string" +#define STRING_ASM_OP "\t.string\t" #undef SKIP_ASM_OP -#define SKIP_ASM_OP "\t.zero" +#define SKIP_ASM_OP "\t.zero\t" #undef GLOBAL_ASM_OP -#define GLOBAL_ASM_OP "\t.globl" +#define GLOBAL_ASM_OP "\t.globl\t" #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) +#define EH_FRAME_SECTION_NAME_COFF ".ehfram" +#define EH_FRAME_SECTION_NAME_ELF ".eh_frame" +#define EH_FRAME_SECTION_NAME \ + ((TARGET_ELF) ? EH_FRAME_SECTION_NAME_ELF : EH_FRAME_SECTION_NAME_COFF) /* Avoid problems (long sectino names, forward assembler refs) with DWARF exception unwinding when we're generating COFF */ @@ -101,7 +95,8 @@ Boston, MA 02111-1307, USA. */ #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\"" +/* Rename these for COFF because crt1.o will try to run them. */ +#define INIT_SECTION_ASM_OP_COFF "\t.section\t.ctor ,\"x\"" #define INIT_SECTION_ASM_OP \ ((TARGET_ELF) ? INIT_SECTION_ASM_OP_ELF : INIT_SECTION_ASM_OP_COFF) @@ -119,7 +114,7 @@ Boston, MA 02111-1307, USA. */ #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_COFF "\t.section\t.dtor, \"x\"" #define FINI_SECTION_ASM_OP \ ((TARGET_ELF) ? FINI_SECTION_ASM_OP_ELF : FINI_SECTION_ASM_OP_COFF) @@ -152,7 +147,7 @@ do { \ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ do { \ if (TARGET_ELF) { \ - fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "%s", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ @@ -168,7 +163,7 @@ do { \ do { \ if (TARGET_ELF) { if (!flag_inhibit_size_directive) \ { \ - fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, (FNAME)); \ fprintf (FILE, ",.-"); \ assemble_name (FILE, (FNAME)); \ @@ -180,7 +175,7 @@ do { \ #define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ do { \ if (TARGET_ELF) { \ - fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "%s", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ @@ -189,7 +184,7 @@ do { \ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ { \ size_directive_output = 1; \ - fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, NAME); \ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ } \ @@ -208,26 +203,18 @@ do { \ 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); \ + const 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); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ assemble_name (FILE, name); \ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ } \ @@ -238,24 +225,15 @@ do { \ #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); \ + sprintf (LABEL, "*.%s%ld", (PREFIX), (long)(NUM)); \ else \ - fprintf (FILE, "\t.word %s%d-%s%d\n", LPREFIX,VALUE,LPREFIX,REL); \ + sprintf (LABEL, ".%s%ld", (PREFIX), (long)(NUM)); \ } while (0) #undef ASM_OUTPUT_ALIGNED_COMMON #define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ do { \ - fprintf ((FILE), "%s\t", COMMON_ASM_OP); \ + fprintf ((FILE), "%s", COMMON_ASM_OP); \ assemble_name ((FILE), (NAME)); \ if (TARGET_ELF) \ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ @@ -267,7 +245,7 @@ do { \ #define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ do { \ if (TARGET_ELF) { \ - fprintf ((FILE), "%s\t", LOCAL_ASM_OP); \ + fprintf ((FILE), "%s", LOCAL_ASM_OP); \ assemble_name ((FILE), (NAME)); \ fprintf ((FILE), "\n"); \ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \ @@ -311,9 +289,10 @@ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) #define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ do \ { \ - register unsigned char *_limited_str = (unsigned char *) (STR); \ + register const unsigned char *_limited_str = \ + (const unsigned char *) (STR); \ register unsigned ch; \ - fprintf ((FILE), "%s\t\"", STRING_ASM_OP); \ + fprintf ((FILE), "%s\"", STRING_ASM_OP); \ for (; (ch = *_limited_str); _limited_str++) \ { \ register int escape; \ @@ -339,12 +318,13 @@ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) #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 const unsigned char *_ascii_bytes = \ + (const unsigned char *) (STR); \ + register const unsigned char *limit = _ascii_bytes + (LENGTH); \ register unsigned bytes_in_chunk = 0; \ for (; _ascii_bytes < limit; _ascii_bytes++) \ { \ - register unsigned char *p; \ + register unsigned const char *p; \ if (bytes_in_chunk >= 64) \ { \ fputc ('\n', (FILE)); \ @@ -352,7 +332,7 @@ do { \ } \ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ continue; \ - if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + if (p < limit && (p - _ascii_bytes) <= (long) STRING_LIMIT) \ { \ if (bytes_in_chunk > 0) \ { \ @@ -365,7 +345,7 @@ do { \ else \ { \ if (bytes_in_chunk == 0) \ - fprintf ((FILE), "%s\t", ASM_BYTE_OP); \ + fputs ("\t.byte\t", (FILE)); \ else \ fputc (',', (FILE)); \ fprintf ((FILE), "0x%02x", *_ascii_bytes); \ @@ -378,10 +358,10 @@ do { \ /* Must use data section for relocatable constants when pic. */ #undef SELECT_RTX_SECTION -#define SELECT_RTX_SECTION(MODE,RTX) \ +#define SELECT_RTX_SECTION(MODE,RTX,ALIGN) \ { \ if (TARGET_ELF) { \ - if (flag_pic && symbolic_operand (RTX)) \ + if (flag_pic && symbolic_operand (RTX, VOIDmode)) \ data_section (); \ else \ const_section (); \ @@ -397,45 +377,13 @@ do { \ 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); + fprintf (FILE, "%s\"%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)) + (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) \ @@ -445,70 +393,27 @@ do { \ #define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ fprintf (FILE, ".%s%d:\n", PREFIX, NUM) -/* The prefix to add to user-visible assembler symbols. */ +/* 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 + * 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) +/* #define EXCEPTION_SECTION() named_section (NULL, ".gccexc", 1) */ + +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section #undef ASM_OUTPUT_SKIP #define ASM_OUTPUT_SKIP(FILE,SIZE) \ do { \ if (TARGET_ELF) \ - fprintf (FILE, "%s\t%u\n", SKIP_ASM_OP, (SIZE)); \ + fprintf (FILE, "%s%u\n", SKIP_ASM_OP, (SIZE)); \ else \ - fprintf ((FILE), "%s\t.,.+%u\n", SET_ASM_OP, (SIZE)); \ + fprintf ((FILE), "%s.,.+%u\n", SET_ASM_OP, (SIZE)); \ } while (0) @@ -540,57 +445,36 @@ do { \ #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)) +#define DBX_REGISTER_NUMBER(n) \ + ((TARGET_ELF) ? svr4_dbx_register_map[n] : dbx_register_map[n]) +#undef DWARF2_DEBUGGING_INFO #undef DWARF_DEBUGGING_INFO #undef SDB_DEBUGGING_INFO #undef DBX_DEBUGGING_INFO #undef PREFERRED_DEBUGGING_TYPE +#define DWARF2_DEBUGGING_INFO 1 #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) + ((TARGET_ELF) ? DWARF2_DEBUG: SDB_DEBUG) #undef EXTRA_SECTIONS -#define EXTRA_SECTIONS in_const, in_init, in_fini, in_ctors, in_dtors +#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 \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION + FINI_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) \ @@ -624,38 +508,11 @@ init_section () \ } \ } -#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 \ +#undef SUBTARGET_FRAME_POINTER_REQUIRED +#define SUBTARGET_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) ? "" : ".") @@ -679,7 +536,7 @@ dtors_section () \ #undef RETURN_POPS_ARGS #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \ ((TARGET_ELF) ? \ - (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE)) : \ + (ix86_return_pops_args (FUNDECL, FUNTYPE, SIZE)) : \ (((FUNDECL) && (TREE_CODE (FUNDECL) == IDENTIFIER_NODE)) ? 0 \ : (TARGET_RTD \ && (TYPE_ARG_TYPES (FUNTYPE) == 0 \ @@ -688,7 +545,7 @@ dtors_section () \ : 0)) #undef SELECT_SECTION -#define SELECT_SECTION(DECL,RELOC) \ +#define SELECT_SECTION(DECL,RELOC,ALIGN) \ { \ if (TARGET_ELF && flag_pic && RELOC) \ data_section (); \ @@ -724,14 +581,15 @@ dtors_section () \ && strcmp (STR, "Tdata") && strcmp (STR, "Ttext") \ && strcmp (STR, "Tbss")) -#undef TARGET_DEFAULT -#define TARGET_DEFAULT (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS) +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_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 +/* Though OpenServer supports .weak in COFF, we don't use it. + * G++ will frequently emit a symol as .weak and then (in the same .s + * file) declare it global. The COFF assembler finds this unamusing. */ #define SUPPORTS_WEAK (TARGET_ELF) #define ASM_WEAKEN_LABEL(FILE,NAME) \ @@ -793,7 +651,7 @@ dtors_section () \ #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 + * Undef MD_EXEC_PREFIX because we don't know where GAS is, but it's not * likely in /usr/ccs/bin/ */ #undef MD_EXEC_PREFIX @@ -835,7 +693,7 @@ dtors_section () \ #undef CPP_PREDEFINES #define CPP_PREDEFINES \ - "-Asystem(svr3)" + "-Asystem=svr3" /* You are in a maze of GCC specs ... all alike */ @@ -890,7 +748,7 @@ dtors_section () \ %{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. */ + and "-o foo". So we just always force a single space. */ #define SWITCHES_NEED_SPACES "o" @@ -906,18 +764,16 @@ dtors_section () \ "%{!shared:-lgcc}" #define MASK_COFF 010000000000 /* Mask for elf generation */ -#define TARGET_COFF (target_flags & MASK_COFF) -#define TARGET_ELF (!(target_flags & MASK_COFF)) +#define TARGET_ELF (1) /* (!(target_flags & MASK_COFF)) */ #undef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES \ - { "coff", MASK_COFF, "Generate COFF output" }, \ - { "elf", -MASK_COFF, "Generate ELF output" }, +#define SUBTARGET_SWITCHES \ + { "elf", -MASK_COFF, N_("Generate ELF output") }, #define NO_DOLLAR_IN_LABEL /* Implicit library calls should use memcpy, not bcopy, etc. They are - faster on OpenServer libraries. */ + faster on OpenServer libraries. */ #define TARGET_MEM_FUNCTIONS @@ -928,6 +784,13 @@ dtors_section () \ #define MAX_OFILE_ALIGNMENT (32768*8) +/* Define the `__builtin_va_list' type for the ABI. On OpenServer, this + type is `char *'. */ +#undef BUILD_VA_LIST_TYPE +#define BUILD_VA_LIST_TYPE(VALIST) \ + (VALIST) = build_pointer_type (char_type_node) + + /* 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 @@ -940,30 +803,28 @@ 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 EH_FRAME_SECTION_NAME # 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 +# define EH_FRAME_SECTION_NAME EH_FRAME_SECTION_NAME_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 EH_FRAME_SECTION_NAME EH_FRAME_SECTION_NAME_COFF # define CTOR_LIST_BEGIN asm (INIT_SECTION_ASM_OP); asm ("pushl $0") # define CTOR_LIST_END CTOR_LIST_BEGIN # define DO_GLOBAL_CTORS_BODY \ @@ -974,3 +835,44 @@ do { \ } while (0) # endif /* ! _SCO_ELF */ #endif /* CRT_BEGIN !! CRT_END */ + +/* Handle special EH pointer encodings. Absolute, pc-relative, and + indirect are handled automatically. */ +#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \ + do { \ + if ((SIZE) == 4 && ((ENCODING) & 0x70) == DW_EH_PE_datarel) \ + { \ + fputs (ASM_LONG, FILE); \ + assemble_name (FILE, XSTR (ADDR, 0)); \ + fputs (((ENCODING) & DW_EH_PE_indirect ? "@GOT" : "@GOTOFF"), FILE); \ + goto DONE; \ + } \ + } while (0) + +/* Used by crtstuff.c to initialize the base of data-relative relocations. + These are GOT relative on x86, so return the pic register. */ +#ifdef __PIC__ +#define CRT_GET_RFIB_DATA(BASE) \ + { \ + register void *ebx_ __asm__("ebx"); \ + BASE = ebx_; \ + } +#else +#define CRT_GET_RFIB_DATA(BASE) \ + __asm__ ("call\t.LPR%=\n" \ + ".LPR%=:\n\t" \ + "popl\t%0\n\t" \ + /* Due to a GAS bug, this cannot use EAX. That encodes \ + smaller than the traditional EBX, which results in the \ + offset being off by one. */ \ + "addl\t$_GLOBAL_OFFSET_TABLE_+[.-.LPR%=],%0" \ + : "=d"(BASE)) +#endif + +/* Select a format to encode pointers in exception handling data. CODE + is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is + true if the symbol may be affected by dynamic relocations. */ +#undef ASM_PREFERRED_EH_DATA_FORMAT +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \ + (flag_pic ? (GLOBAL ? DW_EH_PE_indirect : 0) | DW_EH_PE_datarel \ + : DW_EH_PE_absptr) diff --git a/contrib/gcc/config/i386/scodbx.h b/contrib/gcc/config/i386/scodbx.h index d7d03f8..7da9305 100644 --- a/contrib/gcc/config/i386/scodbx.h +++ b/contrib/gcc/config/i386/scodbx.h @@ -31,8 +31,8 @@ Boston, MA 02111-1307, USA. */ 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) +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) /* Use crt1.o as a startup file and crtn.o as a closing file. */ @@ -50,10 +50,10 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dunix -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(svr3)" +#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}" +#define CPP_SPEC "%(cpp_cpu) %{scointl:-DM_INTERNAT}" /* This spec is used for telling cpp whether char is signed or not. */ @@ -66,10 +66,6 @@ Boston, MA 02111-1307, USA. */ "%{!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. */ @@ -84,9 +80,5 @@ Boston, MA 02111-1307, USA. */ /* 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/contrib/gcc/config/i386/seq-gas.h b/contrib/gcc/config/i386/seq-gas.h index 796eaa2..d11c4c1 100644 --- a/contrib/gcc/config/i386/seq-gas.h +++ b/contrib/gcc/config/i386/seq-gas.h @@ -1,7 +1,7 @@ /* Definitions for Sequent Intel 386 using GAS. Copyright (C) 1992 Free Software Foundation, Inc. -/* Mostly it's like a Sequent 386 without GAS. */ +/* Mostly it's like a Sequent 386 without GAS. */ #include "i386/sequent.h" @@ -37,10 +37,10 @@ count is in %cl. Some assemblers require %cl as an argument; some don't. - GAS requires the %cl argument, so override i386/unix.h. */ + 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. */ +/* Print opcodes the way that GAS expects them. */ #define GAS_MNEMONICS 1 diff --git a/contrib/gcc/config/i386/seq-sysv3.h b/contrib/gcc/config/i386/seq-sysv3.h index 9e8388d..c8e7592 100644 --- a/contrib/gcc/config/i386/seq-sysv3.h +++ b/contrib/gcc/config/i386/seq-sysv3.h @@ -19,24 +19,27 @@ %{fshared-data:-lpps -lseq} -lc crtend.o%s" #undef CPP_SPEC -#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} -D_SEQUENT_=1" +#define CPP_SPEC "%(cpp_cpu) %{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). */ +/* Assembler pseudo-op for initialized shared variables (.shdata). */ #undef SHARED_SECTION_ASM_OP -#define SHARED_SECTION_ASM_OP ".section .shdata, \"ws\"" +#define SHARED_SECTION_ASM_OP "\t.section .shdata, \"ws\"" -/* Assembler pseudo-op for uninitialized shared global variables (.shbss). */ +/* 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). */ +/* Assembler pseudo-op for uninitialized shared local variables (.shbss). */ #undef SHARED_BSS_SECTION_ASM_OP -#define SHARED_BSS_SECTION_ASM_OP ".section .shbss, \"bs\"" +#define SHARED_BSS_SECTION_ASM_OP "\t.section .shbss, \"bs\"" + +/* seq2-sysv3.h used to define HAVE_ATEXIT, so I assume ptx1 needs this... */ +#define NEED_ATEXIT diff --git a/contrib/gcc/config/i386/seq2-sysv3.h b/contrib/gcc/config/i386/seq2-sysv3.h index 763c5f0..dd43af7 100644 --- a/contrib/gcc/config/i386/seq2-sysv3.h +++ b/contrib/gcc/config/i386/seq2-sysv3.h @@ -4,5 +4,4 @@ /* Use atexit for static destructors, instead of defining our own exit function. */ -#define HAVE_ATEXIT - +#undef NEED_ATEXIT diff --git a/contrib/gcc/config/i386/sequent.h b/contrib/gcc/config/i386/sequent.h index 8613ad7..cffc50a 100644 --- a/contrib/gcc/config/i386/sequent.h +++ b/contrib/gcc/config/i386/sequent.h @@ -1,5 +1,5 @@ /* Definitions for Sequent Intel 386. - Copyright (C) 1988, 1994, 1999 Free Software Foundation, Inc. + Copyright (C) 1988, 1994, 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -28,12 +28,12 @@ Boston, MA 02111-1307, USA. */ 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) +#undef TARGET_SUBTARGET_DEFAULT +#define TARGET_SUBTARGET_DEFAULT (MASK_80387 | MASK_FLOAT_RETURNS) /* Specify predefined symbols in preprocessor. */ -#define CPP_PREDEFINES "-Dunix -Di386 -Dsequent -Asystem(unix) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-Dunix -Dsequent -Asystem=unix" /* Pass -Z and -ZO options to the linker. */ @@ -64,10 +64,6 @@ Boston, MA 02111-1307, USA. */ * 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 \ @@ -77,13 +73,13 @@ Boston, MA 02111-1307, USA. */ 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); \ + 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); \ + fprintf (asmfile, "%s%d,0,%d,", ASM_STABN_OP, N_RBRAC, depth); \ assemble_name (asmfile, buf); \ fprintf (asmfile, "\n"); @@ -100,14 +96,14 @@ Boston, MA 02111-1307, USA. */ && ! (REGNO == 2 && GET_MODE_UNIT_SIZE (MODE) > 4)) /* Output assembler code to FILE to increment profiler label # LABELNO - for profiling a function entry. */ + 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" +/* Assembler pseudo-op for shared data segment. */ +#define SHARED_SECTION_ASM_OP "\t.shdata" /* A C statement or statements which output an assembler instruction opcode to the stdio stream STREAM. The macro-operand PTR is a @@ -139,13 +135,13 @@ Boston, MA 02111-1307, USA. */ #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER)\ - sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*.%s%ld", (PREFIX), (long)(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. */ +/* 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/contrib/gcc/config/i386/sol2-c1.asm b/contrib/gcc/config/i386/sol2-c1.asm index d08bcbd..b17f57d9 100644 --- a/contrib/gcc/config/i386/sol2-c1.asm +++ b/contrib/gcc/config/i386/sol2-c1.asm @@ -115,6 +115,12 @@ _start: ! is the argument vector pointer, which is at a fixed address off ! the initial frame pointer. +! +! Make sure the stack is properly aligned. +! + andl $0xfffffff0,%esp + subl $4,%esp + pushl %edx leal 12(%ebp),%edx pushl %edx diff --git a/contrib/gcc/config/i386/sol2-gc1.asm b/contrib/gcc/config/i386/sol2-gc1.asm index 24a1965..81b56d4 100644 --- a/contrib/gcc/config/i386/sol2-gc1.asm +++ b/contrib/gcc/config/i386/sol2-gc1.asm @@ -128,6 +128,12 @@ _start: ! is the argument vector pointer, which is at a fixed address off ! the initial frame pointer. +! +! Make sure the stack is properly aligned. +! + andl $0xfffffff0,%esp + subl $4,%esp + pushl %edx leal 12(%ebp),%edx pushl %edx diff --git a/contrib/gcc/config/i386/sol2.h b/contrib/gcc/config/i386/sol2.h index b254a10..fb9d745 100644 --- a/contrib/gcc/config/i386/sol2.h +++ b/contrib/gcc/config/i386/sol2.h @@ -1,5 +1,6 @@ /* Target definitions for GNU compiler for Intel 80386 running Solaris 2 - Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. Contributed by Fred Fish (fnf@cygnus.com). This file is part of GNU CC. @@ -19,7 +20,6 @@ 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" /* We use stabs-in-elf for debugging, because that is what the native toolchain uses. */ @@ -55,23 +55,54 @@ Boston, MA 02111-1307, USA. */ 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. */ + it knows what it is doing. */ +#define FORCE_CODE_SECTION_ALIGN asm(ALIGN_ASM_OP "16"); -#define FORCE_INIT_SECTION_ALIGN asm (ALIGN_ASM_OP ## " 16") -#define FORCE_FINI_SECTION_ALIGN FORCE_INIT_SECTION_ALIGN +/* Select a format to encode pointers in exception handling data. CODE + is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is + true if the symbol may be affected by dynamic relocations. */ +#undef ASM_PREFERRED_EH_DATA_FORMAT +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \ + (flag_pic ? (GLOBAL ? DW_EH_PE_indirect : 0) | DW_EH_PE_datarel \ + : DW_EH_PE_absptr) + +/* Solaris 2/Intel uses a wint_t different from the default, as on SPARC. */ +#undef WINT_TYPE +#define WINT_TYPE "long int" + +#undef WINT_TYPE_SIZE +#define WINT_TYPE_SIZE BITS_PER_WORD /* Add "sun" to the list of symbols defined for SVR4. */ #undef CPP_PREDEFINES #define CPP_PREDEFINES \ - "-Dunix -D__svr4__ -D__SVR4 -Dsun -Asystem(svr4)" + "-Dunix -D__svr4__ -D__SVR4 -Dsun -Asystem=svr4" +/* Solaris 2/Intel as chokes on #line directives. */ #undef CPP_SPEC -#define CPP_SPEC "%(cpp_cpu) \ +#define CPP_SPEC \ + "%{.S:-P} \ + %(cpp_cpu) \ + %{pthreads:-D_REENTRANT -D_PTHREADS} \ + %{!pthreads:%{threads:-D_REENTRANT -D_SOLARIS_THREADS}} \ %{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude}" +/* For C++ we need to add some additional macro definitions required + by the C++ standard library. */ +#define CPLUSPLUS_CPP_SPEC "\ +-D_XOPEN_SOURCE=500 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 \ +-D__EXTENSIONS__ \ +%(cpp) \ +" + #undef LIB_SPEC #define LIB_SPEC \ - "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} %{!shared:%{!symbolic:-lc}}" + "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} \ + %{!shared:\ + %{!symbolic:\ + %{pthreads:-lpthread} \ + %{!pthreads:%{threads:-lthread}} \ + -lc}}" #undef ENDFILE_SPEC #define ENDFILE_SPEC "crtend.o%s %{pg:crtn.o%s}%{!pg:crtn.o%s}" @@ -93,20 +124,20 @@ Boston, MA 02111-1307, USA. */ "%{h*} %{v:-V} \ %{b} %{Wl,*:%*} \ %{static:-dn -Bstatic} \ - %{shared:-G -dy -z text} \ + %{shared:-G -dy %{!mimpure-text:-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} \ + %{!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}}}} \ + %{!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. @@ -119,7 +150,7 @@ Boston, MA 02111-1307, USA. */ || (CHAR) == 'h' \ || (CHAR) == 'z') -#define STDC_0_IN_SYSTEM_HEADERS +#define STDC_0_IN_SYSTEM_HEADERS 1 #undef LOCAL_LABEL_PREFIX #define LOCAL_LABEL_PREFIX "." diff --git a/contrib/gcc/config/i386/sol2gas.h b/contrib/gcc/config/i386/sol2gas.h index 558183a..f8ca103 100644 --- a/contrib/gcc/config/i386/sol2gas.h +++ b/contrib/gcc/config/i386/sol2gas.h @@ -7,3 +7,5 @@ #ifndef GAS_REJECTS_MINUS_S #define GAS_REJECTS_MINUS_S 1 #endif + +/* Assume sol2.h will be included afterwards. */ diff --git a/contrib/gcc/config/i386/sun.h b/contrib/gcc/config/i386/sun.h index ecc0e82..de40abb 100644 --- a/contrib/gcc/config/i386/sun.h +++ b/contrib/gcc/config/i386/sun.h @@ -44,7 +44,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ -#define CPP_PREDEFINES "-Dunix -Di386 -Dsun386 -Dsun -Asystem(unix) -Asystem(bsd) -Acpu(i386) -Amachine(i386)" +#define CPP_PREDEFINES "-Dunix -Dsun386 -Dsun -Asystem=unix -Asystem=bsd" /* Allow #sccs in preprocessor. */ diff --git a/contrib/gcc/config/i386/sun386.h b/contrib/gcc/config/i386/sun386.h index 4302ec4..d280d58 100644 --- a/contrib/gcc/config/i386/sun386.h +++ b/contrib/gcc/config/i386/sun386.h @@ -1,5 +1,5 @@ /* Definitions for Sun assembler syntax for the Intel 80386. - Copyright (C) 1988, 1996 Free Software Foundation, Inc. + Copyright (C) 1988, 1996, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -33,21 +33,21 @@ Boston, MA 02111-1307, USA. */ /* 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" +#define ASM_SHORT "\t.value\t" +#define ASM_LONG "\t.long\t" +#define ASM_QUAD "\t.quad\t" /* Should not be used for 32bit compilation. */ + /* How to output an ASCII string constant. */ -#define ASM_OUTPUT_ASCII(FILE, p, size) \ +#define ASM_OUTPUT_ASCII(FILE, PTR, SIZE) \ do \ -{ int i = 0; \ - while (i < (size)) \ +{ size_t i = 0, limit = (SIZE); \ + while (i < limit) \ { if (i%10 == 0) { if (i!=0) fprintf ((FILE), "\n"); \ - fprintf ((FILE), "%s ", ASM_BYTE_OP); } \ + fputs ("\t.byte\t", (FILE)); } \ else fprintf ((FILE), ","); \ - fprintf ((FILE), "0x%x", ((p)[i++] & 0377)) ;} \ + fprintf ((FILE), "0x%x", ((PTR)[i++] & 0377)) ;} \ fprintf ((FILE), "\n"); \ } while (0) @@ -57,10 +57,9 @@ do \ #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; \ + const int len = strlen (main_input_filename); \ + const char *na = main_input_filename + len; \ char shorter[15]; \ /* NA gets MAIN_INPUT_FILENAME sans directory names. */\ while (na > main_input_filename) \ @@ -76,7 +75,7 @@ do \ fprintf (FILE, "\n"); \ } \ fprintf (FILE, "\t.version\t\"%s %s\"\n", \ - language_string, version_string); \ + lang_hooks.name, version_string); \ if (optimize) ASM_FILE_START_1 (FILE); \ } while (0) @@ -98,12 +97,12 @@ do \ /* Output before read-only data. */ #undef TEXT_SECTION_ASM_OP -#define TEXT_SECTION_ASM_OP ".text" +#define TEXT_SECTION_ASM_OP "\t.text" /* Output before writable data. */ #undef DATA_SECTION_ASM_OP -#define DATA_SECTION_ASM_OP ".data" +#define DATA_SECTION_ASM_OP "\t.data" /* Define the syntax of labels and symbol definitions/declarations. */ @@ -129,9 +128,9 @@ do \ This is suitable for output with `assemble_name'. */ #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*.%s%ld", (PREFIX), (long)(NUMBER)) -/* The prefix to add to user-visible assembler symbols. */ +/* The prefix to add to user-visible assembler symbols. */ #define USER_LABEL_PREFIX "" diff --git a/contrib/gcc/config/i386/svr3dbx.h b/contrib/gcc/config/i386/svr3dbx.h index 36c01cc..b0e4237 100644 --- a/contrib/gcc/config/i386/svr3dbx.h +++ b/contrib/gcc/config/i386/svr3dbx.h @@ -33,7 +33,7 @@ Boston, MA 02111-1307, USA. */ #undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \ - sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER)) + sprintf ((BUF), "*.%s%ld", (PREFIX), (long)(NUMBER)) /* With the current gas, .align N aligns to an N-byte boundary. This is done to be compatible with the system assembler. diff --git a/contrib/gcc/config/i386/svr3gas.h b/contrib/gcc/config/i386/svr3gas.h index a288b84..08ada11 100644 --- a/contrib/gcc/config/i386/svr3gas.h +++ b/contrib/gcc/config/i386/svr3gas.h @@ -1,5 +1,5 @@ /* Definitions for Intel 386 running system V, using gas. - Copyright (C) 1992, 1996 Free Software Foundation, Inc. + Copyright (C) 1992, 1996, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -37,8 +37,8 @@ Boston, MA 02111-1307, USA. */ 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 \ +#undef SUBTARGET_FRAME_POINTER_REQUIRED +#define SUBTARGET_FRAME_POINTER_REQUIRED \ (current_function_calls_setjmp || current_function_calls_longjmp) /* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib, adapted to gas */ @@ -94,27 +94,22 @@ Boston, MA 02111-1307, USA. */ 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 INIT_SECTION_ASM_OP "\t.section\t.init" +#define FINI_SECTION_ASM_OP "\t.section .fini,\"x\"" +#define CONST_SECTION_ASM_OP "\t.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. */ +/* This is copied from i386/sysv3.h. */ -#ifdef STACK_GROWS_DOWNWARD +#define CTOR_LIST_BEGIN \ + asm (INIT_SECTION_ASM_OP); \ + asm ("pushl $0") +#define CTOR_LIST_END CTOR_LIST_BEGIN /* 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. */ @@ -127,18 +122,6 @@ do { \ (*--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 @@ -156,7 +139,7 @@ init_section () \ { \ if (in_section != in_init) \ { \ - fprintf (asm_out_file, "\t%s\n", INIT_SECTION_ASM_OP); \ + fprintf (asm_out_file, "%s\n", INIT_SECTION_ASM_OP); \ in_section = in_init; \ } \ } @@ -167,7 +150,7 @@ fini_section () \ { \ if (in_section != in_fini) \ { \ - fprintf (asm_out_file, "\t%s\n", FINI_SECTION_ASM_OP); \ + fprintf (asm_out_file, "%s\n", FINI_SECTION_ASM_OP); \ in_section = in_fini; \ } \ } @@ -178,7 +161,6 @@ fini_section () \ void \ const_section () \ { \ - extern void text_section(); \ if (!USE_CONST_SECTION) \ text_section(); \ else if (in_section != in_const) \ @@ -188,51 +170,14 @@ const_section () \ } \ } -/* 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) +#define TARGET_ASM_CONSTRUCTOR ix86_svr3_asm_out_constructor /* 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) \ +#define SELECT_SECTION(DECL,RELOC,ALIGN) \ { \ if (TREE_CODE (DECL) == STRING_CST) \ { \ @@ -262,32 +207,4 @@ dtors_section () \ 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) +#define SELECT_RTX_SECTION(MODE,RTX,ALIGN) const_section() diff --git a/contrib/gcc/config/i386/sysv3.h b/contrib/gcc/config/i386/sysv3.h index ce89889..8eb4bec 100644 --- a/contrib/gcc/config/i386/sysv3.h +++ b/contrib/gcc/config/i386/sysv3.h @@ -1,5 +1,5 @@ /* Definitions for Intel 386 running system V. - Copyright (C) 1988, 1996 Free Software Foundation, Inc. + Copyright (C) 1988, 1996, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -42,7 +42,7 @@ Boston, MA 02111-1307, USA. */ /* Specify predefined symbols in preprocessor. */ -#define CPP_PREDEFINES "-Dunix -Asystem(svr3)" +#define CPP_PREDEFINES "-Dunix -Asystem=svr3" #define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE}" @@ -78,8 +78,8 @@ Boston, MA 02111-1307, USA. */ 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 \ +#undef SUBTARGET_FRAME_POINTER_REQUIRED +#define SUBTARGET_FRAME_POINTER_REQUIRED \ (current_function_calls_setjmp || current_function_calls_longjmp) /* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib. */ @@ -102,23 +102,14 @@ Boston, MA 02111-1307, USA. */ 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. */ + push a word containing 0 (or some equivalent of that). */ #undef INIT_SECTION_ASM_OP -#define INIT_SECTION_ASM_OP ".section .init,\"x\"" +#define INIT_SECTION_ASM_OP "\t.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) +#define TARGET_ASM_CONSTRUCTOR ix86_svr3_asm_out_constructor diff --git a/contrib/gcc/config/i386/sysv4.h b/contrib/gcc/config/i386/sysv4.h index e688f7b..7dc0ac1 100644 --- a/contrib/gcc/config/i386/sysv4.h +++ b/contrib/gcc/config/i386/sysv4.h @@ -1,5 +1,5 @@ /* Target definitions for GNU compiler for Intel 80386 running System V.4 - Copyright (C) 1991 Free Software Foundation, Inc. + Copyright (C) 1991, 2001 Free Software Foundation, Inc. Written by Ron Guilmette (rfg@netcom.com). @@ -20,9 +20,6 @@ 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)"); @@ -32,68 +29,14 @@ Boston, MA 02111-1307, USA. */ #undef RETURN_IN_MEMORY #define RETURN_IN_MEMORY(TYPE) \ - (TYPE_MODE (TYPE) == BLKmode) + (TYPE_MODE (TYPE) == BLKmode \ + || (VECTOR_MODE_P (TYPE_MODE (TYPE)) && int_size_in_bytes (TYPE) == 8)) /* 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) + "-Dunix -D__svr4__ -Asystem=unix -Asystem=svr4" /* Output at beginning of assembler file. */ /* The .file command should always begin the output. */ @@ -105,82 +48,8 @@ do { long value[3]; \ 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)) +#define DBX_REGISTER_NUMBER(n) svr4_dbx_register_map[n] /* 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 @@ -193,12 +62,13 @@ do { long value[3]; \ #define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \ do \ { \ - register unsigned char *_ascii_bytes = (unsigned char *) (STR); \ - register unsigned char *limit = _ascii_bytes + (LENGTH); \ + register const unsigned char *_ascii_bytes = \ + (const unsigned char *) (STR); \ + register const unsigned char *limit = _ascii_bytes + (LENGTH); \ register unsigned bytes_in_chunk = 0; \ for (; _ascii_bytes < limit; _ascii_bytes++) \ { \ - register unsigned char *p; \ + register const unsigned char *p; \ if (bytes_in_chunk >= 64) \ { \ fputc ('\n', (FILE)); \ @@ -206,7 +76,7 @@ do { long value[3]; \ } \ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \ continue; \ - if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \ + if (p < limit && (p - _ascii_bytes) <= (long) STRING_LIMIT) \ { \ if (bytes_in_chunk > 0) \ { \ @@ -231,19 +101,6 @@ do { long value[3]; \ } \ 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. @@ -251,3 +108,39 @@ do { long value[3]; \ #define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) + +/* Handle special EH pointer encodings. Absolute, pc-relative, and + indirect are handled automatically. */ +#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \ + do { \ + if ((SIZE) == 4 && ((ENCODING) & 0x70) == DW_EH_PE_datarel) \ + { \ + fputs (ASM_LONG, FILE); \ + assemble_name (FILE, XSTR (ADDR, 0)); \ + fputs (((ENCODING) & DW_EH_PE_indirect ? "@GOT" : "@GOTOFF"), FILE); \ + goto DONE; \ + } \ + } while (0) + +/* Used by crtstuff.c to initialize the base of data-relative relocations. + These are GOT relative on x86, so return the pic register. */ +#ifdef __PIC__ +#define CRT_GET_RFIB_DATA(BASE) \ + { \ + register void *ebx_ __asm__("ebx"); \ + BASE = ebx_; \ + } +#else +#define CRT_GET_RFIB_DATA(BASE) \ + __asm__ ("call\t.LPR%=\n" \ + ".LPR%=:\n\t" \ + "popl\t%0\n\t" \ + /* Due to a GAS bug, this cannot use EAX. That encodes \ + smaller than the traditional EBX, which results in the \ + offset being off by one. */ \ + "addl\t$_GLOBAL_OFFSET_TABLE_+[.-.LPR%=],%0" \ + : "=d"(BASE)) +#endif + +#undef CPP_SPEC +#define CPP_SPEC "%(cpp_cpu)" diff --git a/contrib/gcc/config/i386/sysv5.h b/contrib/gcc/config/i386/sysv5.h index 09a3bbe..87d6b9c 100644 --- a/contrib/gcc/config/i386/sysv5.h +++ b/contrib/gcc/config/i386/sysv5.h @@ -20,8 +20,6 @@ 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 @@ -29,7 +27,8 @@ Boston, MA 02111-1307, USA. */ /* Add -lcrt for Dwarf2 abbreviation table */ #undef LIB_SPEC -#define LIB_SPEC "%{pthread:-lthread} %{!shared:%{!symbolic:-lc -lcrt}}" +#define LIB_SPEC "%{pthread:-lthread} %{pthreadT:-lthreadT} \ + %{!shared:%{!symbolic:-lc -lcrt}}" #undef CPP_SPEC -#define CPP_SPEC "%{pthread:-D_REENTRANT}" +#define CPP_SPEC "%(cpp_cpu) %{pthread:-D_REENTRANT} %{pthreadT:-D_REENTRANT}" diff --git a/contrib/gcc/config/i386/t-beos b/contrib/gcc/config/i386/t-beos new file mode 100644 index 0000000..e545abd --- /dev/null +++ b/contrib/gcc/config/i386/t-beos @@ -0,0 +1,7 @@ +# There are system headers elsewhere, but these are the ones that +# we are most likely to want to apply any fixes to. +SYSTEM_HEADER_DIR = /boot/develop/headers/posix +CROSS_SYSTEM_HEADER_DIR = $(tooldir)/sys-include/posix + +# Don't run fixproto +STMP_FIXPROTO = diff --git a/contrib/gcc/config/i386/t-cygwin b/contrib/gcc/config/i386/t-cygwin index 175f66b..68d2ac5 100644 --- a/contrib/gcc/config/i386/t-cygwin +++ b/contrib/gcc/config/i386/t-cygwin @@ -1,5 +1,3 @@ -LIBGCC1 = libgcc1-asm.a -CROSS_LIBGCC1 = libgcc1-asm.a LIB1ASMSRC = i386/cygwin.asm LIB1ASMFUNCS = _chkstk @@ -7,10 +5,17 @@ LIB1ASMFUNCS = _chkstk # the build, it may not be installed yet. LIMITS_H_TEST = true +T_CPPFLAGS=-DCYGWIN_CROSS_DIR=\"$(build_tooldir)\" + # 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 +LIBGCC2_INCLUDES = -I$(srcdir)/../winsup/include \ + -I$(srcdir)/../winsup/cygwin/include \ + -I$(srcdir)/../winsup/w32api/include -winnt.o: $(srcdir)/config/i386/winnt.c +winnt.o: $(srcdir)/config/i386/winnt.c $(RTL_H) $(TREE_H) $(CONFIG_H) $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/winnt.c + +# Don't run fixproto +STMP_FIXPROTO = diff --git a/contrib/gcc/config/i386/t-dgux b/contrib/gcc/config/i386/t-dgux index 1bf024a..e1bccee 100644 --- a/contrib/gcc/config/i386/t-dgux +++ b/contrib/gcc/config/i386/t-dgux @@ -6,3 +6,6 @@ EXTRA_PARTS=crti.o crtbegin.o crtend.o 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 + +# Don't run fixproto +STMP_FIXPROTO = diff --git a/contrib/gcc/config/i386/t-djgpp b/contrib/gcc/config/i386/t-djgpp index 6160b7e..7b54b7b 100644 --- a/contrib/gcc/config/i386/t-djgpp +++ b/contrib/gcc/config/i386/t-djgpp @@ -1,2 +1,2 @@ -LIBGCC1 = libgcc1.null -CROSS_LIBGCC1 = libgcc1.null +# Location of DJGPP's header directory. +NATIVE_SYSTEM_HEADER_DIR=$(DJDIR)/include diff --git a/contrib/gcc/config/i386/t-i386elf b/contrib/gcc/config/i386/t-i386elf new file mode 100644 index 0000000..9560d90 --- /dev/null +++ b/contrib/gcc/config/i386/t-i386elf @@ -0,0 +1,4 @@ +# For svr4 we build crtbegin.o and crtend.o which serve to add begin and +# end labels to the .ctors and .dtors section when we link using gcc. + +EXTRA_PARTS=crtbegin.o crtend.o diff --git a/contrib/gcc/config/i386/t-interix b/contrib/gcc/config/i386/t-interix index 4c6d84f..3f78f78 100644 --- a/contrib/gcc/config/i386/t-interix +++ b/contrib/gcc/config/i386/t-interix @@ -1,7 +1,3 @@ -# t-interix -LIBGCC1 = libgcc1-asm.a -CROSS_LIBGCC1 = libgcc1-asm.a - LIB1ASMSRC = i386/cygwin.asm LIB1ASMFUNCS = _chkstk @@ -9,8 +5,4 @@ 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= +USER_H= diff --git a/contrib/gcc/config/i386/t-next b/contrib/gcc/config/i386/t-next index effa695..4b70ba7 100644 --- a/contrib/gcc/config/i386/t-next +++ b/contrib/gcc/config/i386/t-next @@ -1,7 +1,3 @@ -# 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 diff --git a/contrib/gcc/config/i386/t-openbsd b/contrib/gcc/config/i386/t-openbsd new file mode 100644 index 0000000..1830463 --- /dev/null +++ b/contrib/gcc/config/i386/t-openbsd @@ -0,0 +1,6 @@ +# gdb gets confused if pic code is linked with non pic +# We cope by building variants of libgcc. +MULTILIB_OPTIONS = fpic +MULTILIB_MATCHES=fpic=fPIC +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib diff --git a/contrib/gcc/config/i386/t-rtems-i386 b/contrib/gcc/config/i386/t-rtems-i386 new file mode 100644 index 0000000..d301ed9 --- /dev/null +++ b/contrib/gcc/config/i386/t-rtems-i386 @@ -0,0 +1,14 @@ +# +# This file was based on t-sol2 - x68 Solaris implementation. Actually, +# the source code to create crti.o anf crtn.o are exactly the same +# as the ones for Solaris. Later, we might want to have a RTEMS's +# version of these files. +# + +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 + diff --git a/contrib/gcc/config/i386/t-sco5 b/contrib/gcc/config/i386/t-sco5 index f602066..d0c457e 100644 --- a/contrib/gcc/config/i386/t-sco5 +++ b/contrib/gcc/config/i386/t-sco5 @@ -1,20 +1,18 @@ -# 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 +# 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. Likewise for libgcc2.c. This is less painful +# than multilibbing everything with PIC and PIC-not variants. -# -# 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 = +# The pushl in CTOR initialization interferes with frame pointer elimination. -LIBGCC=stmp-multilib -INSTALL_LIBGCC=install-multilib +CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer +TARGET_LIBGCC2_CFLAGS = -fPIC 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 + +# See all the declarations. +FIXPROTO_DEFINES = -D_XOPEN_SOURCE -D_POSIX_C_SOURCE=2 diff --git a/contrib/gcc/config/i386/t-sco5gas b/contrib/gcc/config/i386/t-sco5gas index 2bca87b..2d0b48a 100644 --- a/contrib/gcc/config/i386/t-sco5gas +++ b/contrib/gcc/config/i386/t-sco5gas @@ -18,3 +18,6 @@ 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 + +# See all the declarations. +FIXPROTO_DEFINES = -D_XOPEN_SOURCE -D_POSIX_C_SOURCE=2 diff --git a/contrib/gcc/config/i386/t-sol2 b/contrib/gcc/config/i386/t-sol2 index 5dc59cc..5d7522c 100644 --- a/contrib/gcc/config/i386/t-sol2 +++ b/contrib/gcc/config/i386/t-sol2 @@ -1,9 +1,3 @@ -# 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) \ diff --git a/contrib/gcc/config/i386/udk.h b/contrib/gcc/config/i386/udk.h index 8e03abf..66f5b87 100644 --- a/contrib/gcc/config/i386/udk.h +++ b/contrib/gcc/config/i386/udk.h @@ -6,8 +6,6 @@ /* 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/" diff --git a/contrib/gcc/config/i386/unix.h b/contrib/gcc/config/i386/unix.h index 771d802..15a0701 100644 --- a/contrib/gcc/config/i386/unix.h +++ b/contrib/gcc/config/i386/unix.h @@ -1,5 +1,5 @@ /* Definitions for Unix assembler syntax for the Intel 80386. - Copyright (C) 1988, 1994, 1999 Free Software Foundation, Inc. + Copyright (C) 1988, 1994, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -22,79 +22,13 @@ Boston, MA 02111-1307, USA. */ 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 DEFAULT_ASSEMBLER_DIALECT 0 /* 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. */ @@ -114,15 +48,15 @@ Boston, MA 02111-1307, USA. */ /* Output before read-only data. */ -#define TEXT_SECTION_ASM_OP ".text" +#define TEXT_SECTION_ASM_OP "\t.text" /* Output before writable (initialized) data. */ -#define DATA_SECTION_ASM_OP ".data" +#define DATA_SECTION_ASM_OP "\t.data" /* Output before writable (uninitialized) data. */ -#define BSS_SECTION_ASM_OP ".bss" +#define BSS_SECTION_ASM_OP "\t.bss" /* This is how to output a command to make the user-level label named NAME defined for reference from other files. */ @@ -133,58 +67,69 @@ Boston, MA 02111-1307, USA. */ /* 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) +#define TARGET_SUBTARGET_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)) + && TARGET_FLOAT_RETURNS_IN_80387 ? FIRST_FLOAT_REG \ + : (MODE) == TImode || VECTOR_MODE_P (MODE) ? FIRST_SSE_REG \ + : 0) /* 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"); \ - } \ +#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \ +do { \ + tree parm; \ + rtx xops[3]; \ + \ + if (ix86_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; \ + \ + xops[0] = GEN_INT (DELTA); \ + if (parm) \ + xops[1] = gen_rtx_REG (SImode, 0); \ + else if (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION)))) \ + xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8)); \ + else \ + xops[1] = gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4)); \ + output_asm_insn ("add{l} {%0, %1|%1, %0}", xops); \ + \ + if (flag_pic && !TARGET_64BIT) \ + { \ + xops[0] = pic_offset_table_rtx; \ + xops[1] = gen_label_rtx (); \ + xops[2] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); \ + \ + if (ix86_regparm > 2) \ + abort (); \ + output_asm_insn ("push{l}\t%0", xops); \ + output_asm_insn ("call\t%P1", xops); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", CODE_LABEL_NUMBER (xops[1])); \ + output_asm_insn ("pop{l}\t%0", xops); \ + output_asm_insn ("add{l}\t{%2+[.-%P1], %0|%0, OFFSET FLAT: %2+[.-%P1]}", xops); \ + xops[0] = gen_rtx_MEM (SImode, XEXP (DECL_RTL (FUNCTION), 0)); \ + output_asm_insn ("mov{l}\t{%0@GOT(%%ebx), %%ecx|%%ecx, %0@GOT[%%ebx]}",\ + xops); \ + asm_fprintf (FILE, "\tpop{l\t%%ebx|\t%%ebx}\n"); \ + asm_fprintf (FILE, "\tjmp\t{*%%ecx|%%ecx}\n"); \ + } \ + else if (flag_pic && TARGET_64BIT) \ + { \ + fprintf (FILE, "\tjmp *"); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "@GOTPCREL(%%rip)\n"); \ + } \ + else \ + { \ + fprintf (FILE, "\tjmp "); \ + assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \ + fprintf (FILE, "\n"); \ + } \ } while (0) diff --git a/contrib/gcc/config/i386/uwin.asm b/contrib/gcc/config/i386/uwin.asm index 6268343..8566be1 100644 --- a/contrib/gcc/config/i386/uwin.asm +++ b/contrib/gcc/config/i386/uwin.asm @@ -1,4 +1,4 @@ -/* stuff needed for libgcc1 on win32. */ +/* stuff needed for libgcc on win32. */ #ifdef L_chkstk diff --git a/contrib/gcc/config/i386/uwin.h b/contrib/gcc/config/i386/uwin.h index 73e04ad..ca39ffd 100644 --- a/contrib/gcc/config/i386/uwin.h +++ b/contrib/gcc/config/i386/uwin.h @@ -20,7 +20,7 @@ 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. */ +Boston, MA 02111-1307, USA. */ /* Most of this is the same as for Cygwin32, except for changing some specs. */ @@ -29,9 +29,11 @@ Boston, MA 02111-1307, USA. */ #define STANDARD_INCLUDE_COMPONENT "UWIN" #define SYSTEM_INCLUDE_DIR "/usr/gnu/include" +#undef MD_STARTFILE_PREFIX +#define MD_STARTFILE_PREFIX "/usr/gnu/lib/" #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-D__i386__ -D_WIN32 -D__WIN32__ \ +#define CPP_PREDEFINES "-D_WIN32 -D__WIN32__ \ -D_UWIN -DWINNT -D_X86_=1 -D__STDC__=1 \ -D__UWIN__ -D__MSVCRT__ \ -D_STD_INCLUDE_DIR=mingw32 \ @@ -39,7 +41,7 @@ Boston, MA 02111-1307, USA. */ _D_stdcall=__attribute__((__stdcall__)) \ -D__cdecl=__attribute__((__cdecl__)) \ -D__declspec(x)=__attribute__((x)) \ - -Asystem(winnt) -Acpu(i386) -Amachine(i386)" + -Asystem=winnt" #undef CPP_SPEC #define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ @@ -50,9 +52,9 @@ Boston, MA 02111-1307, USA. */ kernel32. */ #undef LIB_SPEC #define LIB_SPEC \ - "%{mwindows:-luser32 -lgdi32 -lcomdlg32} -lkernel32 -ladvapi32" + "%{pg:-lgmon} %{mwindows:-luser32 -lgdi32 -lcomdlg32} -lkernel32 -ladvapi32" -/* This is needed in g77spec.c for now. Will be removed in the future. */ +/* 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 */ @@ -62,25 +64,24 @@ Boston, MA 02111-1307, USA. */ /* Specify a different entry point when linking a DLL */ #undef LINK_SPEC #define LINK_SPEC \ - "%{mwindows:--subsystem windows} %{mdll:--dll -e _DllMainCRTStartup@12}" + "%{mwindows:--subsystem windows} %{mdll:--dll -e _DllMainCRTStartup@12} \ + %{!mdll:-u _main}" #undef STARTFILE_SPEC -#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s}" +#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s} %{pg:gcrt2%O%s}" -/* These are PE BFD bug workarounds. Should go away eventually. */ +/* These are PE BFD bug workarounds. Should go away eventually. */ +/* 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); \ - } \ - /* disable i386_pe_declare_function_type for UWIN */ \ + i386_pe_record_exported_symbol (NAME, 0); \ + /* UWIN binutils bug workaround. */ \ if (0 && write_symbols != SDB_DEBUG) \ i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ ASM_OUTPUT_LABEL (FILE, NAME); \ @@ -89,5 +90,8 @@ Boston, MA 02111-1307, USA. */ #undef ASM_OUTPUT_EXTERNAL #undef ASM_OUTPUT_EXTERNAL_LIBCALL -#undef ASM_FILE_END + +/* Override Cygwin's definition. This is necessary now due to the way + Cygwin profiling code is written. Once "fixed", we can remove this. */ +#undef SUBTARGET_PROLOGUE diff --git a/contrib/gcc/config/i386/v3gas.h b/contrib/gcc/config/i386/v3gas.h index fe558d2..a350ab4 100644 --- a/contrib/gcc/config/i386/v3gas.h +++ b/contrib/gcc/config/i386/v3gas.h @@ -37,8 +37,8 @@ Boston, MA 02111-1307, USA. */ 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 \ +#undef SUBTARGET_FRAME_POINTER_REQUIRED +#define SUBTARGET_FRAME_POINTER_REQUIRED \ (current_function_calls_setjmp || current_function_calls_longjmp) /* Modify ASM_OUTPUT_LOCAL slightly to test -msvr3-shlib, adapted to gas */ diff --git a/contrib/gcc/config/i386/vsta.h b/contrib/gcc/config/i386/vsta.h index ee7fab9..1bb897d 100644 --- a/contrib/gcc/config/i386/vsta.h +++ b/contrib/gcc/config/i386/vsta.h @@ -26,53 +26,4 @@ Boston, MA 02111-1307, USA. */ #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) - - +#define CPP_PREDEFINES "-Dunix -DVSTA -Asystem=unix -Asystem=vsta" diff --git a/contrib/gcc/config/i386/vxi386.h b/contrib/gcc/config/i386/vxi386.h index 0bd27b4..c050ca7 100644 --- a/contrib/gcc/config/i386/vxi386.h +++ b/contrib/gcc/config/i386/vxi386.h @@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */ #undef CPP_CPU_SPEC #define CPP_CPU_SPEC "\ --Asystem(unix) -Acpu(i386) -Amachine(i386) \ +-Asystem=unix -Acpu=i386 -Amachine=i386 \ %{!ansi:-Di386} -D__i386 -D__i386__ \ %{march=i386:-DCPU=I80386} \ %{march=i486:-DCPU=I80486 %(cpp_486)} \ @@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */ #define HANDLE_SYSV_PRAGMA #undef CPP_PREDEFINES -#define CPP_PREDEFINES "-D__vxworks -D__i386__" +#define CPP_PREDEFINES "-D__vxworks" /* VxWorks does all the library stuff itself. */ @@ -48,7 +48,7 @@ Boston, MA 02111-1307, USA. */ #define LIB_SPEC "" /* VxWorks uses object files, not loadable images. make linker just - combine objects. */ + combine objects. */ #undef LINK_SPEC #define LINK_SPEC "-r" diff --git a/contrib/gcc/config/i386/win32.h b/contrib/gcc/config/i386/win32.h index d62abbf..0aa7a57 100644 --- a/contrib/gcc/config/i386/win32.h +++ b/contrib/gcc/config/i386/win32.h @@ -2,7 +2,8 @@ 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. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 + Free Software Foundation, Inc. This file is part of GNU CC. @@ -19,7 +20,7 @@ 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. */ +Boston, MA 02111-1307, USA. */ #define YES_UNDERSCORES @@ -33,7 +34,7 @@ Boston, MA 02111-1307, USA. */ #include "i386/gas.h" #include "dbxcoff.h" -/* Augment TARGET_SWITCHES with the cygwin/win32 options. */ +/* 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 */ @@ -47,21 +48,25 @@ Boston, MA 02111-1307, USA. */ #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, "" }, +#define SUBTARGET_SWITCHES \ + { "win32", MASK_WIN32, \ + N_("Use Mingw32 interface") }, \ + { "cygwin", MASK_CYGWIN, \ + N_("Use Cygwin interface") }, \ + { "windows", MASK_WINDOWS, \ + N_("Use bare Windows interface") }, \ + { "dll", MASK_DLL, \ + N_("Generate code for a DLL") }, \ + { "nop-fun-dllimport", MASK_NOP_FUN_DLLIMPORT, \ + N_("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\ +#define CPP_PREDEFINES "-D_WIN32 -DWINNT -D_X86_=1 \ -D__stdcall=__attribute__((__stdcall__)) \ -D__cdecl=__attribute__((__cdecl__)) \ - -Asystem(winnt)" + -Asystem=winnt" #undef STARTFILE_SPEC @@ -97,53 +102,6 @@ Boston, MA 02111-1307, USA. */ 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 @@ -155,7 +113,7 @@ dtor_section () \ 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. */ + attribute STDCALL. */ #ifdef ENCODE_SECTION_INFO #undef ENCODE_SECTION_INFO @@ -186,16 +144,17 @@ while (0) #undef STRIP_NAME_ENCODING #define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ do { \ - char *_p; \ - char *_name = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*')); \ + const char *_p; \ + const char *const _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'; \ + char *_new_name = (char *) alloca (_len + 1); \ + strncpy (_new_name, _name, _len); \ + _new_name[_len] = '\0'; \ + (VAR) = _new_name; \ } \ else \ (VAR) = _name; \ @@ -203,15 +162,15 @@ do { \ /* Emit code to check the stack when allocating more that 4000 - bytes in one go. */ + 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 +#undef TARGET_SUBTARGET_DEFAULT -#define TARGET_DEFAULT \ +#define TARGET_SUBTARGET_DEFAULT \ (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE) /* This is how to output an assembler line @@ -228,53 +187,29 @@ do { \ 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) +/* Switch into a generic section. */ +#define TARGET_ASM_NAMED_SECTION i386_pe_asm_named_section + +/* Select attributes for named sections. */ +#define TARGET_SECTION_TYPE_FLAGS i386_pe_section_type_flags #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. */ +/* 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) \ + if (current_function_profile \ + && MAIN_NAME_P (DECL_NAME (current_function_decl)) \ { \ 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); \ + emit_call_insn (gen_rtx (CALL, VOIDmode, xops[0], const0_rtx)); \ } diff --git a/contrib/gcc/config/i386/winnt.c b/contrib/gcc/config/i386/winnt.c index 24d8617..9d955df 100644 --- a/contrib/gcc/config/i386/winnt.c +++ b/contrib/gcc/config/i386/winnt.c @@ -1,6 +1,6 @@ /* 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. + Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -27,6 +27,9 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "tree.h" #include "flags.h" +#include "tm_p.h" +#include "toplev.h" +#include "hashtab.h" /* i386/PE specific attribute support. @@ -39,102 +42,61 @@ Boston, MA 02111-1307, USA. */ 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. */ +static tree associated_type PARAMS ((tree)); +const char * gen_stdcall_suffix PARAMS ((tree)); +int i386_pe_dllexport_p PARAMS ((tree)); +int i386_pe_dllimport_p PARAMS ((tree)); +void i386_pe_mark_dllexport PARAMS ((tree)); +void i386_pe_mark_dllimport PARAMS ((tree)); -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; +/* Handle a "dllimport" or "dllexport" attribute; + arguments as in struct attribute_spec.handler. */ +tree +ix86_handle_dll_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; tree args; + int flags; + bool *no_add_attrs; { - if (args == NULL_TREE - && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) + /* These attributes may apply to structure and union types being created, + but otherwise should pass to the declaration involved. */ + if (!DECL_P (*node)) { - if (is_attribute_p ("dllexport", attr)) - return 1; - if (is_attribute_p ("dllimport", attr)) - return 1; + if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_ARRAY_NEXT)) + { + *no_add_attrs = true; + return tree_cons (name, args, NULL_TREE); + } + if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE) + { + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } } - return i386_valid_type_attribute_p (type, attributes, attr, args); + return NULL_TREE; } -/* 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. */ - +/* Handle a "shared" attribute; + arguments as in struct attribute_spec.handler. */ tree -i386_pe_merge_decl_attributes (old, new) - tree old, new; +ix86_handle_shared_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; { - 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) + if (TREE_CODE (*node) != VAR_DECL) { - 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; - } - } + warning ("`%s' attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; } - return a; + return NULL_TREE; } /* Return the type that we should use to determine if DECL is @@ -173,7 +135,7 @@ i386_pe_dllexport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); + exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); if (exp) return 1; @@ -204,7 +166,7 @@ i386_pe_dllimport_p (decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return 0; - imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); + imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)); if (imp) return 1; @@ -224,7 +186,7 @@ i386_pe_dllimport_p (decl) int i386_pe_dllexport_name_p (symbol) - char *symbol; + const char *symbol; { return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; } @@ -233,7 +195,7 @@ i386_pe_dllexport_name_p (symbol) int i386_pe_dllimport_name_p (symbol) - char *symbol; + const char *symbol; { return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; } @@ -245,7 +207,8 @@ void i386_pe_mark_dllexport (decl) tree decl; { - char *oldname, *newname; + const char *oldname; + char *newname; rtx rtlname; tree idp; @@ -281,7 +244,8 @@ void i386_pe_mark_dllimport (decl) tree decl; { - char *oldname, *newname; + const char *oldname; + char *newname; tree idp; rtx rtlname, newrtl; @@ -295,7 +259,7 @@ i386_pe_mark_dllimport (decl) abort (); if (i386_pe_dllexport_name_p (oldname)) { - error ("`%s' declared as both exported to and imported from a DLL.", + error ("`%s' declared as both exported to and imported from a DLL", IDENTIFIER_POINTER (DECL_NAME (decl))); return; } @@ -368,14 +332,14 @@ i386_pe_mark_dllimport (decl) suffix consisting of an atsign (@) followed by the number of bytes of arguments */ -char * +const 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)); + const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); char *newsym; if (TYPE_ARG_TYPES (TREE_TYPE (decl))) @@ -442,7 +406,7 @@ i386_pe_encode_section_info (decl) && 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); + const 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)); @@ -463,7 +427,8 @@ i386_pe_unique_section (decl, reloc) int reloc; { int len; - char *name,*string,*prefix; + const char *name, *prefix; + char *string; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); /* Strip off any encoding in fnname. */ @@ -477,6 +442,9 @@ i386_pe_unique_section (decl, reloc) without a .rdata section. */ if (TREE_CODE (decl) == FUNCTION_DECL) prefix = ".text$"; +/* else if (DECL_INITIAL (decl) == 0 + || DECL_INITIAL (decl) == error_mark_node) + prefix = ".bss"; */ else if (DECL_READONLY_SECTION (decl, reloc)) #ifdef READONLY_DATA_SECTION prefix = ".rdata$"; @@ -491,6 +459,98 @@ i386_pe_unique_section (decl, reloc) DECL_SECTION_NAME (decl) = build_string (len, string); } + +/* Select a set of attributes for section NAME based on the properties + of DECL and whether or not RELOC indicates that DECL's initializer + might contain runtime relocations. + + 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. + + If the section has already been defined, to not allow it to have + different attributes, as (1) this is ambiguous since we're not seeing + all the declarations up front and (2) some assemblers (e.g. SVR4) + do not recoginize section redefinitions. */ +/* ??? This differs from the "standard" PE implementation in that we + handle the SHARED variable attribute. Should this be done for all + PE targets? */ + +#define SECTION_PE_SHARED SECTION_MACH_DEP + +unsigned int +i386_pe_section_type_flags (decl, name, reloc) + tree decl; + const char *name; + int reloc; +{ + static htab_t htab; + unsigned int flags; + unsigned int **slot; + + /* The names we put in the hashtable will always be the unique + versions gived to us by the stringtable, so we can just use + their addresses as the keys. */ + if (!htab) + htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL); + + if (decl && TREE_CODE (decl) == FUNCTION_DECL) + flags = SECTION_CODE; + else if (decl && DECL_READONLY_SECTION (decl, reloc)) + flags = 0; + else + { + flags = SECTION_WRITE; + + if (decl && TREE_CODE (decl) == VAR_DECL + && lookup_attribute ("shared", DECL_ATTRIBUTES (decl))) + flags |= SECTION_PE_SHARED; + } + + if (decl && DECL_ONE_ONLY (decl)) + flags |= SECTION_LINKONCE; + + /* See if we already have an entry for this section. */ + slot = (unsigned int **) htab_find_slot (htab, name, INSERT); + if (!*slot) + { + *slot = (unsigned int *) xmalloc (sizeof (unsigned int)); + **slot = flags; + } + else + { + if (decl && **slot != flags) + error_with_decl (decl, "%s causes a section type conflict"); + } + + return flags; +} + +void +i386_pe_asm_named_section (name, flags) + const char *name; + unsigned int flags; +{ + char flagchars[8], *f = flagchars; + + if (flags & SECTION_CODE) + *f++ = 'x'; + if (flags & SECTION_WRITE) + *f++ = 'w'; + if (flags & SECTION_PE_SHARED) + *f++ = 's'; + *f = '\0'; + + fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars); + + if (flags & SECTION_LINKONCE) + { + /* Functions may have been compiled at various levels of + optimization so we can't use `same_size' here. + Instead, have the linker pick one. */ + fprintf (asm_out_file, "\t.linkonce %s\n", + (flags & SECTION_CODE ? "discard" : "same_size")); + } +} /* The Microsoft linker requires that every function be marked as DT_FCN. When using gas on cygwin, we must emit appropriate .type @@ -507,7 +567,7 @@ i386_pe_unique_section (decl, reloc) void i386_pe_declare_function_type (file, name, public) FILE *file; - char *name; + const char *name; int public; { fprintf (file, "\t.def\t"); @@ -522,7 +582,7 @@ i386_pe_declare_function_type (file, name, public) struct extern_list { struct extern_list *next; - char *name; + const char *name; }; static struct extern_list *extern_head; @@ -535,7 +595,7 @@ static struct extern_list *extern_head; void i386_pe_record_external_function (name) - char *name; + const char *name; { struct extern_list *p; @@ -545,7 +605,16 @@ i386_pe_record_external_function (name) extern_head = p; } -static struct extern_list *exports_head; +/* Keep a list of exported symbols. */ + +struct export_list +{ + struct export_list *next; + const char *name; + int is_data; /* used to type tag exported symbols. */ +}; + +static struct export_list *export_head; /* Assemble an export symbol entry. We need to keep a list of these, so that we can output the export list at the end of the @@ -554,15 +623,17 @@ static struct extern_list *exports_head; linkonce. */ void -i386_pe_record_exported_symbol (name) - char *name; +i386_pe_record_exported_symbol (name, is_data) + const char *name; + int is_data; { - struct extern_list *p; + struct export_list *p; - p = (struct extern_list *) permalloc (sizeof *p); - p->next = exports_head; + p = (struct export_list *) permalloc (sizeof *p); + p->next = export_head; p->name = name; - exports_head = p; + p->is_data = is_data; + export_head = p; } /* This is called at the end of assembly. For each external function @@ -575,6 +646,8 @@ i386_pe_asm_file_end (file) { struct extern_list *p; + ix86_asm_file_end (file); + for (p = extern_head; p != NULL; p = p->next) { tree decl; @@ -589,12 +662,16 @@ i386_pe_asm_file_end (file) } } - if (exports_head) - drectve_section (); - for (p = exports_head; p != NULL; p = p->next) + if (export_head) { - fprintf (file, "\t.ascii \" -export:%s\"\n", - I386_PE_STRIP_ENCODING (p->name)); + struct export_list *q; + drectve_section (); + for (q = export_head; q != NULL; q = q->next) + { + fprintf (file, "\t.ascii \" -export:%s%s\"\n", + I386_PE_STRIP_ENCODING (q->name), + (q->is_data) ? ",data" : ""); + } } } diff --git a/contrib/gcc/config/i386/x86-64.h b/contrib/gcc/config/i386/x86-64.h new file mode 100644 index 0000000..c6a8376 --- /dev/null +++ b/contrib/gcc/config/i386/x86-64.h @@ -0,0 +1,99 @@ +/* OS independent definitions for AMD x86-64. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Bo Thorsen <bo@suse.de>. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#undef ASM_COMMENT_START +#define ASM_COMMENT_START "#" + +#undef DBX_REGISTER_NUMBER +#define DBX_REGISTER_NUMBER(n) \ + (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n]) + +/* Output assembler code to FILE to call the profiler. */ +#define NO_PROFILE_COUNTERS + +#undef FUNCTION_PROFILER +#define FUNCTION_PROFILER(FILE, LABELNO) \ +{ \ + if (TARGET_64BIT && flag_pic) \ + fprintf (FILE, "\tcall\t*mcount@PLT\n"); \ + else if (flag_pic) \ + fprintf (FILE, "\tcall\t*mcount@GOT(%%ebx)\n"); \ + else \ + fprintf (FILE, "\tcall\tmcount\n"); \ +} + +#undef SIZE_TYPE +#define SIZE_TYPE (TARGET_64BIT ? "long unsigned int" : "unsigned int") + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE (TARGET_64BIT ? "long int" : "int") + +#undef WCHAR_TYPE +#define WCHAR_TYPE "int" + +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE 32 + +#undef CC1_SPEC +#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" + +#undef ASM_SPEC +#define ASM_SPEC "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} \ + %{Wa,*:%*} %{m32:--32}" + +/* 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 + + +/* i386 System V Release 4 uses DWARF debugging info. + x86-64 ABI specifies DWARF2. */ + +#undef DWARF2_DEBUGGING_INFO +#undef DWARF_DEBUGGING_INFO +#define DWARF2_DEBUGGING_INFO +#define DWARF2_UNWIND_INFO 1 +/* Incorrectly autodetected in cross compilation. */ +#undef HAVE_AS_DWARF2_DEBUG_LINE +#define HAVE_AS_DWARF2_DEBUG_LINE + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG diff --git a/contrib/gcc/config/i386/xm-cygwin.h b/contrib/gcc/config/i386/xm-cygwin.h index ab59627..721c435 100644 --- a/contrib/gcc/config/i386/xm-cygwin.h +++ b/contrib/gcc/config/i386/xm-cygwin.h @@ -1,6 +1,6 @@ /* 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. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -17,42 +17,19 @@ 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. */ +Boston, MA 02111-1307, USA. */ -#define EXECUTABLE_SUFFIX ".exe" -#define NO_SYS_SIGLIST 1 +#define HOST_EXECUTABLE_SUFFIX ".exe" + +/* Even though Cygwin tries to hide the DOS based filesystem, it + still shows though at times. */ +#define HAVE_DOS_BASED_FILE_SYSTEM /* 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 '/' + perspective of wanting gcc to produce native Win32 paths. */ +#undef DIR_SEPARATOR_2 #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/contrib/gcc/config/i386/xm-dgux.h b/contrib/gcc/config/i386/xm-dgux.h index 5bdb9be..881c5c7 100644 --- a/contrib/gcc/config/i386/xm-dgux.h +++ b/contrib/gcc/config/i386/xm-dgux.h @@ -1,12 +1,4 @@ - /* 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/contrib/gcc/config/i386/xm-djgpp.h b/contrib/gcc/config/i386/xm-djgpp.h index ccf6e3c..71cb116 100644 --- a/contrib/gcc/config/i386/xm-djgpp.h +++ b/contrib/gcc/config/i386/xm-djgpp.h @@ -1,5 +1,5 @@ /* Configuration for GNU C-compiler for Intel 80386 running DJGPP. - Copyright (C) 1988, 1996, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1988, 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -18,27 +18,80 @@ 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" +#define HOST_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 LIBSTDCXX "-lstdcxx" +#define HAVE_DOS_BASED_FILE_SYSTEM -/* System dependant initialization for collect2 +/* System dependent 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) +/* Define a version appropriate for DOS. */ +#undef XREF_FILE_NAME +#define XREF_FILE_NAME(xref_file, file) \ + do { \ + const char xref_ext[] = ".gxref"; \ + strcpy (xref_file, file); \ + s = basename (xref_file); \ + t = strchr (s, '.'); \ + if (t) \ + strcpy (t, xref_ext); \ + else \ + strcat (xref_file, xref_ext); \ + } while (0) + +/* Change /dev/env/DJDIR/prefix/dir/ to canonical form so gcc_exec_prefix + is set properly in 'gcc.c'. It also helps to cut down the number of times + the value of the DJGPP environment variable 'DJDIR' is evaluated. */ +#undef GCC_DRIVER_HOST_INITIALIZATION +#define GCC_DRIVER_HOST_INITIALIZATION \ + do { \ + /* If the environment variable DJDIR is not defined, then DJGPP is not \ + installed correctly and GCC will quickly become confused with the \ + default prefix settings. Report the problem now so the user doesn't \ + receive deceptive "file not found" error messages later. */ \ + char *djdir = getenv ("DJDIR"); \ + if (djdir == NULL) \ + { \ + /* DJDIR is automatically defined by the DJGPP environment config \ + file pointed to by the environment variable DJGPP. Examine DJGPP \ + to try and figure out what's wrong. */ \ + char *djgpp = getenv ("DJGPP"); \ + if (djgpp == NULL) \ + fatal ("environment variable DJGPP not defined"); \ + else if (access (djgpp, R_OK) == 0) \ + fatal ("environment variable DJGPP points to missing file '%s'", \ + djgpp); \ + else \ + fatal ("environment variable DJGPP points to corrupt file '%s'", \ + djgpp); \ + } \ + standard_exec_prefix = update_path (standard_exec_prefix, NULL); \ + standard_bindir_prefix = update_path (standard_bindir_prefix, NULL); \ + standard_startfile_prefix = update_path (standard_startfile_prefix, NULL); \ + } while (0) + +/* Canonicalize paths containing '/dev/env/'; used in prefix.c. + _fixpath is a djgpp-specific function to canonicalize a path. + "/dev/env/DJDIR" evaluates to "c:/djgpp" if DJDIR is "c:/djgpp" for + example. It removes any trailing '/', so add it back. */ +/* We cannot free PATH below as it can point to string constant */ +#define UPDATE_PATH_HOST_CANONICALIZE(PATH) \ + if (memcmp ((PATH), "/dev/env/", sizeof("/dev/env/") - 1) == 0) \ + { \ + static char fixed_path[FILENAME_MAX + 1]; \ + \ + _fixpath ((PATH), fixed_path); \ + strcat (fixed_path, "/"); \ + (PATH) = xstrdup (fixed_path); \ + } diff --git a/contrib/gcc/config/i386/xm-i386-interix.h b/contrib/gcc/config/i386/xm-i386-interix.h index 8bfd5e2..bd010e4 100644 --- a/contrib/gcc/config/i386/xm-i386-interix.h +++ b/contrib/gcc/config/i386/xm-i386-interix.h @@ -21,8 +21,6 @@ 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 diff --git a/contrib/gcc/config/i386/xm-mingw32.h b/contrib/gcc/config/i386/xm-mingw32.h index 6872580..19b102d 100644 --- a/contrib/gcc/config/i386/xm-mingw32.h +++ b/contrib/gcc/config/i386/xm-mingw32.h @@ -1,6 +1,6 @@ /* 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. + Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -17,22 +17,7 @@ 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 +Boston, MA 02111-1307, USA. */ /* Even though we support "/", allow "\" since everybody tests both. */ #define DIR_SEPARATOR '\\' @@ -42,7 +27,7 @@ Boston, MA 02111-1307, USA. */ like Cygwin does. */ #define HAVE_DOS_BASED_FILE_SYSTEM -#define EXECUTABLE_SUFFIX ".exe" +#define HOST_EXECUTABLE_SUFFIX ".exe" #undef PATH_SEPARATOR #define PATH_SEPARATOR ';' diff --git a/contrib/gcc/config/i386/xm-sun.h b/contrib/gcc/config/i386/xm-sun.h index de7c201..6c0f0a2 100644 --- a/contrib/gcc/config/i386/xm-sun.h +++ b/contrib/gcc/config/i386/xm-sun.h @@ -19,5 +19,3 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define USG - -#include "i386/xm-i386.h" diff --git a/contrib/gcc/config/i386/xm-sysv3.h b/contrib/gcc/config/i386/xm-sysv3.h index 72078bb..9a65544 100644 --- a/contrib/gcc/config/i386/xm-sysv3.h +++ b/contrib/gcc/config/i386/xm-sysv3.h @@ -1,4 +1,3 @@ /* Configuration for GCC for Intel i386 running System V Release 3. */ -#include "i386/xm-i386.h" #include "xm-svr3.h" diff --git a/contrib/gcc/config/i386/xmmintrin.h b/contrib/gcc/config/i386/xmmintrin.h new file mode 100644 index 0000000..9f9f2f9 --- /dev/null +++ b/contrib/gcc/config/i386/xmmintrin.h @@ -0,0 +1,1061 @@ +/* Copyright (C) 2002 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. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself 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. */ + +/* Implemented from the specification included in the Intel C++ Compiler + User Guide and Reference, version 5.0. */ + +#ifndef _XMMINTRIN_H_INCLUDED +#define _XMMINTRIN_H_INCLUDED + +/* We need type definitions from the MMX header file. */ +#include <mmintrin.h> + +/* The data type indended for user use. */ +typedef int __m128 __attribute__ ((__mode__(__V4SF__))); + +/* Internal data types for implementing the instrinsics. */ +typedef int __v4sf __attribute__ ((__mode__(__V4SF__))); +typedef int __v4si __attribute__ ((__mode__(__V4SI__))); + +/* Create a selector for use with the SHUFPS instruction. */ +#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) \ + (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | (fp0)) + +/* Constants for use with _mm_prefetch. */ +enum _mm_hint +{ + _MM_HINT_T0 = 3, + _MM_HINT_T1 = 2, + _MM_HINT_T2 = 1, + _MM_HINT_NTA = 0 +}; + +/* Bits in the MXCSR. */ +#define _MM_EXCEPT_MASK 0x003f +#define _MM_EXCEPT_INVALID 0x0001 +#define _MM_EXCEPT_DENORM 0x0002 +#define _MM_EXCEPT_DIV_ZERO 0x0004 +#define _MM_EXCEPT_OVERFLOW 0x0008 +#define _MM_EXCEPT_UNDERFLOW 0x0010 +#define _MM_EXCEPT_INEXACT 0x0020 + +#define _MM_MASK_MASK 0x1f80 +#define _MM_MASK_INVALID 0x0080 +#define _MM_MASK_DENORM 0x0100 +#define _MM_MASK_DIV_ZERO 0x0200 +#define _MM_MASK_OVERFLOW 0x0400 +#define _MM_MASK_UNDERFLOW 0x0800 +#define _MM_MASK_INEXACT 0x1000 + +#define _MM_ROUND_MASK 0x6000 +#define _MM_ROUND_NEAREST 0x0000 +#define _MM_ROUND_DOWN 0x2000 +#define _MM_ROUND_UP 0x4000 +#define _MM_ROUND_TOWARD_ZERO 0x6000 + +#define _MM_FLUSH_ZERO_MASK 0x8000 +#define _MM_FLUSH_ZERO_ON 0x8000 +#define _MM_FLUSH_ZERO_OFF 0x0000 + +/* Perform the respective operation on the lower SPFP (single-precision + floating-point) values of A and B; the upper three SPFP values are + passed through from A. */ + +static __inline __m128 +_mm_add_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_addss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_sub_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_subss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_mul_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_mulss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_div_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_divss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_sqrt_ss (__m128 __A) +{ + return (__m128) __builtin_ia32_sqrtss ((__v4sf)__A); +} + +static __inline __m128 +_mm_rcp_ss (__m128 __A) +{ + return (__m128) __builtin_ia32_rcpss ((__v4sf)__A); +} + +static __inline __m128 +_mm_rsqrt_ss (__m128 __A) +{ + return (__m128) __builtin_ia32_rsqrtss ((__v4sf)__A); +} + +static __inline __m128 +_mm_min_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_minss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_max_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_maxss ((__v4sf)__A, (__v4sf)__B); +} + +/* Perform the respective operation on the four SPFP values in A and B. */ + +static __inline __m128 +_mm_add_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_addps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_sub_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_subps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_mul_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_mulps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_div_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_divps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_sqrt_ps (__m128 __A) +{ + return (__m128) __builtin_ia32_sqrtps ((__v4sf)__A); +} + +static __inline __m128 +_mm_rcp_ps (__m128 __A) +{ + return (__m128) __builtin_ia32_rcpps ((__v4sf)__A); +} + +static __inline __m128 +_mm_rsqrt_ps (__m128 __A) +{ + return (__m128) __builtin_ia32_rsqrtps ((__v4sf)__A); +} + +static __inline __m128 +_mm_min_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_minps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_max_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_maxps ((__v4sf)__A, (__v4sf)__B); +} + +/* Perform logical bit-wise operations on 128-bit values. */ + +static __inline __m128 +_mm_and_ps (__m128 __A, __m128 __B) +{ + return __builtin_ia32_andps (__A, __B); +} + +static __inline __m128 +_mm_andnot_ps (__m128 __A, __m128 __B) +{ + return __builtin_ia32_andnps (__A, __B); +} + +static __inline __m128 +_mm_or_ps (__m128 __A, __m128 __B) +{ + return __builtin_ia32_orps (__A, __B); +} + +static __inline __m128 +_mm_xor_ps (__m128 __A, __m128 __B) +{ + return __builtin_ia32_xorps (__A, __B); +} + +/* Perform a comparison on the lower SPFP values of A and B. If the + comparison is true, place a mask of all ones in the result, otherwise a + mask of zeros. The upper three SPFP values are passed through from A. */ + +static __inline __m128 +_mm_cmpeq_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpeqss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmplt_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpltss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmple_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpless ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpgt_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpgtss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpge_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpgess ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpneq_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpneqss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnlt_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpnltss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnle_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpnless ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpngt_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpngtss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnge_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpngess ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpord_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpordss ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpunord_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpunordss ((__v4sf)__A, (__v4sf)__B); +} + +/* Perform a comparison on the four SPFP values of A and B. For each + element, if the comparison is true, place a mask of all ones in the + result, otherwise a mask of zeros. */ + +static __inline __m128 +_mm_cmpeq_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpeqps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmplt_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpltps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmple_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpleps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpgt_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpgtps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpge_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpgeps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpneq_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpneqps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnlt_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpnltps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnle_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpnleps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpngt_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpngtps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpnge_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpngeps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpord_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpordps ((__v4sf)__A, (__v4sf)__B); +} + +static __inline __m128 +_mm_cmpunord_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_cmpunordps ((__v4sf)__A, (__v4sf)__B); +} + +/* Compare the lower SPFP values of A and B and return 1 if true + and 0 if false. */ + +static __inline int +_mm_comieq_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comieq ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_comilt_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comilt ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_comile_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comile ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_comigt_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comigt ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_comige_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comige ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_comineq_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_comineq ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomieq_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomieq ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomilt_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomilt ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomile_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomile ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomigt_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomigt ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomige_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomige ((__v4sf)__A, (__v4sf)__B); +} + +static __inline int +_mm_ucomineq_ss (__m128 __A, __m128 __B) +{ + return __builtin_ia32_ucomineq ((__v4sf)__A, (__v4sf)__B); +} + +/* Convert the lower SPFP value to a 32-bit integer according to the current + rounding mode. */ +static __inline int +_mm_cvtss_si32 (__m128 __A) +{ + return __builtin_ia32_cvtss2si ((__v4sf) __A); +} + +/* Convert the two lower SPFP values to 32-bit integers according to the + current rounding mode. Return the integers in packed form. */ +static __inline __m64 +_mm_cvtps_pi32 (__m128 __A) +{ + return (__m64) __builtin_ia32_cvtps2pi ((__v4sf) __A); +} + +/* Truncate the lower SPFP value to a 32-bit integer. */ +static __inline int +_mm_cvttss_si32 (__m128 __A) +{ + return __builtin_ia32_cvttss2si ((__v4sf) __A); +} + +/* Truncate the two lower SPFP values to 32-bit integers. Return the + integers in packed form. */ +static __inline __m64 +_mm_cvttps_pi32 (__m128 __A) +{ + return (__m64) __builtin_ia32_cvttps2pi ((__v4sf) __A); +} + +/* Convert B to a SPFP value and insert it as element zero in A. */ +static __inline __m128 +_mm_cvtsi32_ss (__m128 __A, int __B) +{ + return (__m128) __builtin_ia32_cvtsi2ss ((__v4sf) __A, __B); +} + +/* Convert the two 32-bit values in B to SPFP form and insert them + as the two lower elements in A. */ +static __inline __m128 +_mm_cvtpi32_ps (__m128 __A, __m64 __B) +{ + return (__m128) __builtin_ia32_cvtpi2ps ((__v4sf) __A, (__v2si)__B); +} + +/* Convert the four signed 16-bit values in A to SPFP form. */ +static __inline __m128 +_mm_cvtpi16_ps (__m64 __A) +{ + __v4hi __sign; + __v2si __hisi, __losi; + __v4sf __r; + + /* This comparison against zero gives us a mask that can be used to + fill in the missing sign bits in the unpack operations below, so + that we get signed values after unpacking. */ + __sign = (__v4hi) __builtin_ia32_mmx_zero (); + __sign = __builtin_ia32_pcmpgtw (__sign, (__v4hi)__A); + + /* Convert the four words to doublewords. */ + __hisi = (__v2si) __builtin_ia32_punpckhwd ((__v4hi)__A, __sign); + __losi = (__v2si) __builtin_ia32_punpcklwd ((__v4hi)__A, __sign); + + /* Convert the doublewords to floating point two at a time. */ + __r = (__v4sf) __builtin_ia32_setzerops (); + __r = __builtin_ia32_cvtpi2ps (__r, __hisi); + __r = __builtin_ia32_movlhps (__r, __r); + __r = __builtin_ia32_cvtpi2ps (__r, __losi); + + return (__m128) __r; +} + +/* Convert the four unsigned 16-bit values in A to SPFP form. */ +static __inline __m128 +_mm_cvtpu16_ps (__m64 __A) +{ + __v4hi __zero = (__v4hi) __builtin_ia32_mmx_zero (); + __v2si __hisi, __losi; + __v4sf __r; + + /* Convert the four words to doublewords. */ + __hisi = (__v2si) __builtin_ia32_punpckhwd ((__v4hi)__A, __zero); + __losi = (__v2si) __builtin_ia32_punpcklwd ((__v4hi)__A, __zero); + + /* Convert the doublewords to floating point two at a time. */ + __r = (__v4sf) __builtin_ia32_setzerops (); + __r = __builtin_ia32_cvtpi2ps (__r, __hisi); + __r = __builtin_ia32_movlhps (__r, __r); + __r = __builtin_ia32_cvtpi2ps (__r, __losi); + + return (__m128) __r; +} + +/* Convert the low four signed 8-bit values in A to SPFP form. */ +static __inline __m128 +_mm_cvtpi8_ps (__m64 __A) +{ + __v8qi __sign; + + /* This comparison against zero gives us a mask that can be used to + fill in the missing sign bits in the unpack operations below, so + that we get signed values after unpacking. */ + __sign = (__v8qi) __builtin_ia32_mmx_zero (); + __sign = __builtin_ia32_pcmpgtb (__sign, (__v8qi)__A); + + /* Convert the four low bytes to words. */ + __A = (__m64) __builtin_ia32_punpcklbw ((__v8qi)__A, __sign); + + return _mm_cvtpi16_ps(__A); +} + +/* Convert the low four unsigned 8-bit values in A to SPFP form. */ +static __inline __m128 +_mm_cvtpu8_ps(__m64 __A) +{ + __v8qi __zero = (__v8qi) __builtin_ia32_mmx_zero (); + __A = (__m64) __builtin_ia32_punpcklbw ((__v8qi)__A, __zero); + return _mm_cvtpu16_ps(__A); +} + +/* Convert the four signed 32-bit values in A and B to SPFP form. */ +static __inline __m128 +_mm_cvtpi32x2_ps(__m64 __A, __m64 __B) +{ + __v4sf __zero = (__v4sf) __builtin_ia32_setzerops (); + __v4sf __sfa = __builtin_ia32_cvtpi2ps (__zero, (__v2si)__A); + __v4sf __sfb = __builtin_ia32_cvtpi2ps (__zero, (__v2si)__B); + return (__m128) __builtin_ia32_movlhps (__sfa, __sfb); +} + +/* Convert the four SPFP values in A to four signed 16-bit integers. */ +static __inline __m64 +_mm_cvtps_pi16(__m128 __A) +{ + __v4sf __hisf = (__v4sf)__A; + __v4sf __losf = __builtin_ia32_movhlps (__hisf, __hisf); + __v2si __hisi = __builtin_ia32_cvtps2pi (__hisf); + __v2si __losi = __builtin_ia32_cvtps2pi (__losf); + return (__m64) __builtin_ia32_packssdw (__losi, __hisi); +} + +/* Convert the four SPFP values in A to four signed 8-bit integers. */ +static __inline __m64 +_mm_cvtps_pi8(__m128 __A) +{ + __v4hi __tmp = (__v4hi) _mm_cvtps_pi16 (__A); + __v4hi __zero = (__v4hi) __builtin_ia32_mmx_zero (); + return (__m64) __builtin_ia32_packsswb (__tmp, __zero); +} + +/* Selects four specific SPFP values from A and B based on MASK. */ +#if 0 +static __inline __m128 +_mm_shuffle_ps (__m128 __A, __m128 __B, int __mask) +{ + return (__m128) __builtin_ia32_shufps ((__v4sf)__A, (__v4sf)__B, __mask); +} +#else +#define _mm_shuffle_ps(A, B, MASK) \ + ((__m128) __builtin_ia32_shufps ((__v4sf)(A), (__v4sf)(B), (MASK))) +#endif + + +/* Selects and interleaves the upper two SPFP values from A and B. */ +static __inline __m128 +_mm_unpackhi_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_unpckhps ((__v4sf)__A, (__v4sf)__B); +} + +/* Selects and interleaves the lower two SPFP values from A and B. */ +static __inline __m128 +_mm_unpacklo_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_unpcklps ((__v4sf)__A, (__v4sf)__B); +} + +/* Sets the upper two SPFP values with 64-bits of data loaded from P; + the lower two values are passed through from A. */ +static __inline __m128 +_mm_loadh_pi (__m128 __A, __m64 *__P) +{ + return (__m128) __builtin_ia32_loadhps ((__v4sf)__A, (__v2si *)__P); +} + +/* Stores the upper two SPFP values of A into P. */ +static __inline void +_mm_storeh_pi (__m64 *__P, __m128 __A) +{ + __builtin_ia32_storehps ((__v2si *)__P, (__v4sf)__A); +} + +/* Moves the upper two values of B into the lower two values of A. */ +static __inline __m128 +_mm_movehl_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_movhlps ((__v4sf)__A, (__v4sf)__B); +} + +/* Moves the lower two values of B into the upper two values of A. */ +static __inline __m128 +_mm_movelh_ps (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_movlhps ((__v4sf)__A, (__v4sf)__B); +} + +/* Sets the lower two SPFP values with 64-bits of data loaded from P; + the upper two values are passed through from A. */ +static __inline __m128 +_mm_loadl_pi (__m128 __A, __m64 *__P) +{ + return (__m128) __builtin_ia32_loadlps ((__v4sf)__A, (__v2si *)__P); +} + +/* Stores the lower two SPFP values of A into P. */ +static __inline void +_mm_storel_pi (__m64 *__P, __m128 __A) +{ + __builtin_ia32_storelps ((__v2si *)__P, (__v4sf)__A); +} + +/* Creates a 4-bit mask from the most significant bits of the SPFP values. */ +static __inline int +_mm_movemask_ps (__m128 __A) +{ + return __builtin_ia32_movmskps ((__v4sf)__A); +} + +/* Return the contents of the control register. */ +static __inline unsigned int +_mm_getcsr (void) +{ + return __builtin_ia32_stmxcsr (); +} + +/* Read exception bits from the control register. */ +static __inline unsigned int +_MM_GET_EXCEPTION_STATE (void) +{ + return _mm_getcsr() & _MM_EXCEPT_MASK; +} + +static __inline unsigned int +_MM_GET_EXCEPTION_MASK (void) +{ + return _mm_getcsr() & _MM_MASK_MASK; +} + +static __inline unsigned int +_MM_GET_ROUNDING_MODE (void) +{ + return _mm_getcsr() & _MM_ROUND_MASK; +} + +static __inline unsigned int +_MM_GET_FLUSH_ZERO_MODE (void) +{ + return _mm_getcsr() & _MM_FLUSH_ZERO_MASK; +} + +/* Set the control register to I. */ +static __inline void +_mm_setcsr (unsigned int __I) +{ + __builtin_ia32_ldmxcsr (__I); +} + +/* Set exception bits in the control register. */ +static __inline void +_MM_SET_EXCEPTION_STATE(unsigned int __mask) +{ + _mm_setcsr((_mm_getcsr() & ~_MM_EXCEPT_MASK) | __mask); +} + +static __inline void +_MM_SET_EXCEPTION_MASK (unsigned int __mask) +{ + _mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | __mask); +} + +static __inline void +_MM_SET_ROUNDING_MODE (unsigned int __mode) +{ + _mm_setcsr((_mm_getcsr() & ~_MM_ROUND_MASK) | __mode); +} + +static __inline void +_MM_SET_FLUSH_ZERO_MODE (unsigned int __mode) +{ + _mm_setcsr((_mm_getcsr() & ~_MM_FLUSH_ZERO_MASK) | __mode); +} + +/* Create a vector with element 0 as *P and the rest zero. */ +static __inline __m128 +_mm_load_ss (float *__P) +{ + return (__m128) __builtin_ia32_loadss (__P); +} + +/* Create a vector with all four elements equal to *P. */ +static __inline __m128 +_mm_load1_ps (float *__P) +{ + __v4sf __tmp = __builtin_ia32_loadss (__P); + return (__m128) __builtin_ia32_shufps (__tmp, __tmp, _MM_SHUFFLE (0,0,0,0)); +} + +static __inline __m128 +_mm_load_ps1 (float *__P) +{ + return _mm_load1_ps (__P); +} + +/* Load four SPFP values from P. The address must be 16-byte aligned. */ +static __inline __m128 +_mm_load_ps (float *__P) +{ + return (__m128) __builtin_ia32_loadaps (__P); +} + +/* Load four SPFP values from P. The address need not be 16-byte aligned. */ +static __inline __m128 +_mm_loadu_ps (float *__P) +{ + return (__m128) __builtin_ia32_loadups (__P); +} + +/* Load four SPFP values in reverse order. The address must be aligned. */ +static __inline __m128 +_mm_loadr_ps (float *__P) +{ + __v4sf __tmp = __builtin_ia32_loadaps (__P); + return (__m128) __builtin_ia32_shufps (__tmp, __tmp, _MM_SHUFFLE (0,1,2,3)); +} + +/* Create a vector with element 0 as F and the rest zero. */ +static __inline __m128 +_mm_set_ss (float __F) +{ + return (__m128) __builtin_ia32_loadss (&__F); +} + +/* Create a vector with all four elements equal to F. */ +static __inline __m128 +_mm_set1_ps (float __F) +{ + __v4sf __tmp = __builtin_ia32_loadss (&__F); + return (__m128) __builtin_ia32_shufps (__tmp, __tmp, _MM_SHUFFLE (0,0,0,0)); +} + +static __inline __m128 +_mm_set_ps1 (float __F) +{ + return _mm_set1_ps (__F); +} + +/* Create the vector [Z Y X W]. */ +static __inline __m128 +_mm_set_ps (float __Z, float __Y, float __X, float __W) +{ + union { + float __a[4]; + __m128 __v; + } __u; + + __u.__a[0] = __W; + __u.__a[1] = __X; + __u.__a[2] = __Y; + __u.__a[3] = __Z; + + return __u.__v; +} + +/* Create the vector [W X Y Z]. */ +static __inline __m128 +_mm_setr_ps (float __Z, float __Y, float __X, float __W) +{ + return _mm_set_ps (__W, __X, __Y, __Z); +} + +/* Create a vector of zeros. */ +static __inline __m128 +_mm_setzero_ps (void) +{ + return (__m128) __builtin_ia32_setzerops (); +} + +/* Stores the lower SPFP value. */ +static __inline void +_mm_store_ss (float *__P, __m128 __A) +{ + __builtin_ia32_storess (__P, (__v4sf)__A); +} + +/* Store the lower SPFP value across four words. */ +static __inline void +_mm_store1_ps (float *__P, __m128 __A) +{ + __v4sf __va = (__v4sf)__A; + __v4sf __tmp = __builtin_ia32_shufps (__va, __va, _MM_SHUFFLE (0,0,0,0)); + __builtin_ia32_storeaps (__P, __tmp); +} + +static __inline void +_mm_store_ps1 (float *__P, __m128 __A) +{ + _mm_store1_ps (__P, __A); +} + +/* Store four SPFP values. The address must be 16-byte aligned. */ +static __inline void +_mm_store_ps (float *__P, __m128 __A) +{ + __builtin_ia32_storeaps (__P, (__v4sf)__A); +} + +/* Store four SPFP values. The address need not be 16-byte aligned. */ +static __inline void +_mm_storeu_ps (float *__P, __m128 __A) +{ + __builtin_ia32_storeups (__P, (__v4sf)__A); +} + +/* Store four SPFP values in reverse order. The addres must be aligned. */ +static __inline void +_mm_storer_ps (float *__P, __m128 __A) +{ + __v4sf __va = (__v4sf)__A; + __v4sf __tmp = __builtin_ia32_shufps (__va, __va, _MM_SHUFFLE (0,1,2,3)); + __builtin_ia32_storeaps (__P, __tmp); +} + +/* Sets the low SPFP value of A from the low value of B. */ +static __inline __m128 +_mm_move_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_movss ((__v4sf)__A, (__v4sf)__B); +} + +/* Extracts one of the four words of A. The selector N must be immediate. */ +#if 0 +static __inline int +_mm_extract_pi16 (__m64 __A, int __N) +{ + return __builtin_ia32_pextrw ((__v4hi)__A, __N); +} +#else +#define _mm_extract_pi16(A, N) \ + __builtin_ia32_pextrw ((__v4hi)(A), (N)) +#endif + +/* Inserts word D into one of four words of A. The selector N must be + immediate. */ +#if 0 +static __inline __m64 +_mm_insert_pi16 (__m64 __A, int __D, int __N) +{ + return (__m64)__builtin_ia32_pinsrw ((__v4hi)__A, __D, __N); +} +#else +#define _mm_insert_pi16(A, D, N) \ + ((__m64) __builtin_ia32_pinsrw ((__v4hi)(A), (D), (N))) +#endif + +/* Compute the element-wise maximum of signed 16-bit values. */ +static __inline __m64 +_mm_max_pi16 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pmaxsw ((__v4hi)__A, (__v4hi)__B); +} + +/* Compute the element-wise maximum of unsigned 8-bit values. */ +static __inline __m64 +_mm_max_pu8 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pmaxub ((__v8qi)__A, (__v8qi)__B); +} + +/* Compute the element-wise minimum of signed 16-bit values. */ +static __inline __m64 +_mm_min_pi16 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pminsw ((__v4hi)__A, (__v4hi)__B); +} + +/* Compute the element-wise minimum of unsigned 8-bit values. */ +static __inline __m64 +_mm_min_pu8 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pminub ((__v8qi)__A, (__v8qi)__B); +} + +/* Create an 8-bit mask of the signs of 8-bit values. */ +static __inline int +_mm_movemask_pi8 (__m64 __A) +{ + return __builtin_ia32_pmovmskb ((__v8qi)__A); +} + +/* Multiply four unsigned 16-bit values in A by four unsigned 16-bit values + in B and produce the high 16 bits of the 32-bit results. */ +static __inline __m64 +_mm_mulhi_pu16 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pmulhuw ((__v4hi)__A, (__v4hi)__B); +} + +/* Return a combination of the four 16-bit values in A. The selector + must be an immediate. */ +#if 0 +static __inline __m64 +_mm_shuffle_pi16 (__m64 __A, int __N) +{ + return (__m64) __builtin_ia32_pshufw ((__v4hi)__A, __N); +} +#else +#define _mm_shuffle_pi16(A, N) \ + ((__m64) __builtin_ia32_pshufw ((__v4hi)(A), (N))) +#endif + +/* Conditionally store byte elements of A into P. The high bit of each + byte in the selector N determines whether the corresponding byte from + A is stored. */ +static __inline void +_mm_maskmove_si64 (__m64 __A, __m64 __N, char *__P) +{ + __builtin_ia32_maskmovq ((__v8qi)__A, (__v8qi)__N, __P); +} + +/* Compute the rounded averages of the unsigned 8-bit values in A and B. */ +static __inline __m64 +_mm_avg_pu8 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pavgb ((__v8qi)__A, (__v8qi)__B); +} + +/* Compute the rounded averages of the unsigned 16-bit values in A and B. */ +static __inline __m64 +_mm_avg_pu16 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_pavgw ((__v4hi)__A, (__v4hi)__B); +} + +/* Compute the sum of the absolute differences of the unsigned 8-bit + values in A and B. Return the value in the lower 16-bit word; the + upper words are cleared. */ +static __inline __m64 +_mm_sad_pu8 (__m64 __A, __m64 __B) +{ + return (__m64) __builtin_ia32_psadbw ((__v8qi)__A, (__v8qi)__B); +} + +/* Loads one cache line from address P to a location "closer" to the + processor. The selector I specifies the type of prefetch operation. */ +#if 0 +static __inline void +_mm_prefetch (void *__P, enum _mm_hint __I) +{ + __builtin_prefetch (__P, 0, __I); +} +#else +#define _mm_prefetch(P, I) \ + __builtin_prefetch ((P), 0, (I)) +#endif + +/* Stores the data in A to the address P without polluting the caches. */ +static __inline void +_mm_stream_pi (__m64 *__P, __m64 __A) +{ + __builtin_ia32_movntq (__P, __A); +} + +/* Likewise. The address must be 16-byte aligned. */ +static __inline void +_mm_stream_ps (float *__P, __m128 __A) +{ + __builtin_ia32_movntps (__P, (__v4sf)__A); +} + +/* Guarantees that every preceeding store is globally visible before + any subsequent store. */ +static __inline void +_mm_sfence (void) +{ + __builtin_ia32_sfence (); +} + +/* The execution of the next instruction is delayed by an implementation + specific amount of time. The instruction does not modify the + architectural state. */ +static __inline void +_mm_pause (void) +{ + __asm__ __volatile__ ("rep; nop" : : ); +} + +/* Transpose the 4x4 matrix composed of row[0-3]. */ +#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ +do { \ + __v4sf __r0 = (row0), __r1 = (row1), __r2 = (row2), __r3 = (row3); \ + __v4sf __t0 = __builtin_ia32_shufps (__r0, __r1, 0x44); \ + __v4sf __t1 = __builtin_ia32_shufps (__r0, __r1, 0xEE); \ + __v4sf __t2 = __builtin_ia32_shufps (__r2, __r3, 0x44); \ + __v4sf __t3 = __builtin_ia32_shufps (__r2, __r3, 0xEE); \ + (row0) = __builtin_ia32_shufps (__t0, __t1, 0x88); \ + (row1) = __builtin_ia32_shufps (__t0, __t1, 0xDD); \ + (row2) = __builtin_ia32_shufps (__t2, __t3, 0x88); \ + (row3) = __builtin_ia32_shufps (__t2, __t3, 0xDD); \ +} while (0) + +#endif /* _XMMINTRIN_H_INCLUDED */ |