OSDN Git Service

Define SMALL_REGISTER_CLASSES with a value
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.h
index c5f2aa5..241650f 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GNU compiler for Intel X86
    (386, 486, Pentium).
-   Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1994, 1995, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
 
 /* The purpose of this file is to define the characteristics of the i386,
    independent of assembler syntax or operating system.
@@ -52,6 +52,20 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define HALF_PIC_FINISH(STREAM)
 #endif
 
+/* Define the specific costs for a given cpu */
+
+struct processor_costs {
+  int add;                     /* cost of an add instruction */
+  int lea;                     /* cost of a lea instruction */
+  int shift_var;               /* variable shift costs */
+  int shift_const;             /* constant shift costs */
+  int mult_init;               /* cost of starting a multiply */
+  int mult_bit;                        /* cost of multiply per each bit set */
+  int divide;                  /* cost of a divide/mod */
+};
+
+extern struct processor_costs *ix86_cost;
+
 /* Run-time compilation parameters selecting different hardware subsets.  */
 
 extern int target_flags;
@@ -73,12 +87,15 @@ extern int target_flags;
 #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_DEBUG_ARG         000010000000    /* Debug function_arg */   
+#define MASK_NO_PSEUDO         000010000000    /* Move op's args -> pseudos */
+#define MASK_DEBUG_ARG         000020000000    /* Debug function_arg */   
+#define MASK_SCHEDULE_PROLOGUE  000040000000    /* Emit prologue as rtl */
+#define MASK_STACK_PROBE       000100000000    /* Enable stack probing */
 
 /* Use the floating point instructions */
 #define TARGET_80387 (target_flags & MASK_80387)
@@ -111,6 +128,9 @@ extern int target_flags;
    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
@@ -118,6 +138,9 @@ extern int target_flags;
 #define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY)
 #define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY)
 
+/* Emit/Don't emit prologue as rtl */
+#define TARGET_SCHEDULE_PROLOGUE (target_flags & MASK_SCHEDULE_PROLOGUE)
+
 /* Debug GO_IF_LEGITIMATE_ADDRESS */
 #define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR)
 
@@ -126,10 +149,24 @@ extern int target_flags;
 
 /* Hack macros for tuning code generation */
 #define TARGET_MOVE    ((target_flags & MASK_NO_MOVE) == 0)    /* Don't generate memory->memory */
-
-/* Specific hardware switches */
-#define TARGET_486     (target_flags & MASK_486)       /* 80486DX, 80486SX, 80486DX[24] */
-#define TARGET_386     (!TARGET_486)                   /* 80386 */
+#define TARGET_PSEUDO  ((target_flags & MASK_NO_PSEUDO) == 0)  /* Move op's args into pseudos */
+
+#define TARGET_386 (ix86_cpu == PROCESSOR_I386)
+#define TARGET_486 (ix86_cpu == PROCESSOR_I486)
+#define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM)
+#define TARGET_PENTIUMPRO (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_LEAVE (ix86_cpu == PROCESSOR_I386)
+#define TARGET_PUSH_MEMORY (ix86_cpu == PROCESSOR_I386)
+#define TARGET_ZERO_EXTEND_WITH_AND (ix86_cpu != PROCESSOR_I386)
+#define TARGET_DOUBLE_WITH_ADD (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_BIT_TEST (ix86_cpu == PROCESSOR_I386)
+#define TARGET_UNROLL_STRLEN (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_Q_REG (ix86_cpu == PROCESSOR_PENTIUM \
+                         || ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_ANY_REG (ix86_cpu == PROCESSOR_I486)
+#define TARGET_CMOVE (ix86_arch == PROCESSOR_PENTIUMPRO)
+#define TARGET_DEEP_BRANCH_PREDICTION (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
 
 #define TARGET_SWITCHES                                                        \
 { { "80387",                    MASK_80387 },                          \
@@ -137,10 +174,12 @@ extern int target_flags;
   { "hard-float",               MASK_80387 },                          \
   { "soft-float",              -MASK_80387 },                          \
   { "no-soft-float",            MASK_80387 },                          \
-  { "386",                     -MASK_486 },                            \
-  { "no-386",                   MASK_486 },                            \
-  { "486",                      MASK_486 },                            \
-  { "no-486",                  -MASK_486 },                            \
+  { "386",                      0 },                                   \
+  { "no-386",                   0 },                                   \
+  { "486",                      0 },                                   \
+  { "no-486",                   0 },                                   \
+  { "pentium",                  0 },                                   \
+  { "pentiumpro",               0 },                                   \
   { "rtd",                      MASK_RTD },                            \
   { "no-rtd",                  -MASK_RTD },                            \
   { "align-double",             MASK_ALIGN_DOUBLE },                   \
@@ -153,16 +192,60 @@ extern int target_flags;
   { "no-fp-ret-in-387",                -MASK_FLOAT_RETURNS },                  \
   { "no-fancy-math-387",        MASK_NO_FANCY_MATH_387 },              \
   { "fancy-math-387",          -MASK_NO_FANCY_MATH_387 },              \
+  { "omit-leaf-frame-pointer",  MASK_OMIT_LEAF_FRAME_POINTER },        \
+  { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER },       \
   { "no-wide-multiply",                 MASK_NO_WIDE_MULTIPLY },               \
   { "wide-multiply",           -MASK_NO_WIDE_MULTIPLY },               \
+  { "schedule-prologue",        MASK_SCHEDULE_PROLOGUE },              \
+  { "no-schedule-prologue",    -MASK_SCHEDULE_PROLOGUE },              \
   { "debug-addr",               MASK_DEBUG_ADDR },                     \
   { "no-debug-addr",           -MASK_DEBUG_ADDR },                     \
   { "move",                    -MASK_NO_MOVE },                        \
   { "no-move",                  MASK_NO_MOVE },                        \
   { "debug-arg",                MASK_DEBUG_ARG },                      \
   { "no-debug-arg",            -MASK_DEBUG_ARG },                      \
+  { "stack-arg-probe",          MASK_STACK_PROBE },                    \
+  { "no-stack-arg-probe",      -MASK_STACK_PROBE },                    \
   SUBTARGET_SWITCHES                                                   \
-  { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
+  { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT}}
+
+/* Which processor to schedule for. The cpu attribute defines a list that
+   mirrors this list, so changes to i386.md must be made at the same time.  */
+
+enum processor_type
+ {PROCESSOR_I386,                      /* 80386 */
+  PROCESSOR_I486,                      /* 80486DX, 80486SX, 80486DX[24] */
+  PROCESSOR_PENTIUM,
+  PROCESSOR_PENTIUMPRO};
+
+#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"
+
+extern enum processor_type ix86_cpu;
+
+extern int ix86_arch;
+
+/* Define the default processor.  This is overridden by other tm.h files.  */
+#define PROCESSOR_DEFAULT \
+  ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+                                            ? PROCESSOR_I486  \
+  : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+                                              ? PROCESSOR_PENTIUM  \
+  : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+                                              ? PROCESSOR_PENTIUMPRO  \
+  : PROCESSOR_I386
+#define PROCESSOR_DEFAULT_STRING \
+  ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+                                            ? PROCESSOR_I486_STRING  \
+  : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+                                              ? PROCESSOR_PENTIUM_STRING  \
+  : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+                                              ? PROCESSOR_PENTIUMPRO_STRING  \
+  : PROCESSOR_I386_STRING
 
 /* This macro is similar to `TARGET_SWITCHES' but defines names of
    command options that have values.  Its definition is an
@@ -174,11 +257,14 @@ extern int target_flags;
    option if the fixed part matches.  The actual option name is made
    by appending `-m' to the specified name.  */
 #define TARGET_OPTIONS                                                 \
-{ { "reg-alloc=",      &i386_reg_alloc_order },                        \
+{ { "cpu=",            &ix86_cpu_string},                              \
+  { "arch=",           &ix86_arch_string},                             \
+  { "reg-alloc=",      &i386_reg_alloc_order },                        \
   { "regparm=",                &i386_regparm_string },                         \
   { "align-loops=",    &i386_align_loops_string },                     \
   { "align-jumps=",    &i386_align_jumps_string },                     \
   { "align-functions=",        &i386_align_funcs_string },                     \
+  { "branch-cost=",    &i386_branch_cost_string },                     \
   SUBTARGET_OPTIONS                                                    \
 }
 
@@ -197,6 +283,49 @@ extern int target_flags;
 #define SUBTARGET_SWITCHES
 #define SUBTARGET_OPTIONS
 
+/* Define this to change the optimizations performed by default.  */
+#define OPTIMIZATION_OPTIONS(LEVEL) optimization_options(LEVEL)
+
+/* Specs for the compiler proper */
+
+#ifndef CC1_SPEC
+#define CC1_SPEC "\
+%{!mcpu*: \
+%{m386:-mcpu=i386 -march=i386} \
+%{mno-486:-mcpu=i386 -march=i386} \
+%{m486:-mcpu=i486 -march=i486} \
+%{mno-386:-mcpu=i486 -march=i486} \
+%{mno-pentium:-mcpu=i486 -march=i486} \
+%{mpentium:-mcpu=pentium} \
+%{mno-pentiumpro:-mcpu=pentium} \
+%{mpentiumpro:-mcpu=pentiumpro}}"
+#endif
+\f
+#ifndef CPP_CPU_SPEC
+#define CPP_CPU_SPEC "\
+-Di386 -Asystem(unix) -Acpu(i386) -Amachine(i386) \
+%{mcpu=i486:-Di486} %{m486:-Di486} \
+%{mpentium:-Dpentium -Di586} %{mcpu=pentium:-Dpentium -Di586} \
+%{mpentiumpro:-Dpentiumpro -Di686} %{mcpu=pentiumpro:-Dpentiumpro -Di686}"
+#endif
+
+/* This macro defines names of additional specifications to put in the specs
+   that can be used in various specifications like CC1_SPEC.  Its definition
+   is an initializer with a subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the
+   specification name, and a string constant that used by the GNU CC driver
+   program.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS                                                    \
+  { "cpp_cpu", CPP_CPU_SPEC },                                         \
+  SUBTARGET_EXTRA_SPECS
 \f
 /* target machine storage layout */
 
@@ -264,6 +393,9 @@ extern int target_flags;
    aligned on 64 bit boundaries. */
 #define BIGGEST_ALIGNMENT (TARGET_ALIGN_DOUBLE ? 64 : 32)
 
+/* align DFmode constants and nonaggregates */
+#define ALIGN_DFmode (!TARGET_386)
+
 /* Set this non-zero if move instructions will actually fail to work
    when given unaligned data.  */
 #define STRICT_ALIGNMENT 0
@@ -291,6 +423,7 @@ extern int target_flags;
    for details. */
 
 #define STACK_REGS
+#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode)
 
 /* Number of actual hardware registers.
    The hardware registers are assigned numbers for the compiler
@@ -413,8 +546,9 @@ extern int target_flags;
    : 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) <= 12)                      \
-   : (int) (MODE) != (int) QImode)
+      && GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
+   : (int) (MODE) != (int) QImode ? 1                          \
+   : (reload_in_progress | reload_completed) == 1)
 
 /* Value is 1 if it is a good idea to tie two pseudo registers
    when one has mode MODE1 and one has mode MODE2.
@@ -423,17 +557,6 @@ extern int target_flags;
 
 #define MODES_TIEABLE_P(MODE1, MODE2) ((MODE1) == (MODE2))
 
-/* A C expression returning the cost of moving data from a register of class
-   CLASS1 to one of CLASS2.
-
-   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)
-
 /* Specify the registers used for certain standard purposes.
    The values of these macros are register numbers.  */
 
@@ -458,7 +581,7 @@ extern int target_flags;
    Zero means the frame pointer need not be set up (and parms
    may be accessed via the stack pointer) in functions that seem suitable.
    This is computed in `reload', in reload1.c.  */
-#define FRAME_POINTER_REQUIRED 0
+#define FRAME_POINTER_REQUIRED (TARGET_OMIT_LEAF_FRAME_POINTER && !leaf_function_p ())         
 
 /* Base register for access to arguments of the function.  */
 #define ARG_POINTER_REGNUM 16
@@ -566,7 +689,7 @@ enum reg_class
      0x3,                      /* AD_REGS */                   \
      0xf,                      /* Q_REGS */                    \
     0x10,   0x20,              /* SIREG, DIREG */              \
- 0x07f,                                /* INDEX_REGS */                \
+ 0x7f,                         /* INDEX_REGS */                \
  0x100ff,                      /* GENERAL_REGS */              \
   0x0100, 0x0200,              /* FP_TOP_REG, FP_SECOND_REG */ \
   0xff00,                      /* FLOAT_REGS */                \
@@ -583,7 +706,7 @@ enum reg_class
    rtl to be used as spill registers but prevents the compiler from
    extending the lifetime of these registers. */
 
-#define SMALL_REGISTER_CLASSES
+#define SMALL_REGISTER_CLASSES 1
 
 #define QI_REG_P(X) \
   (REG_P (X) && REGNO (X) < 4)
@@ -656,6 +779,8 @@ enum reg_class
    (C) == 'K' ? (VALUE) == 0xff :              \
    (C) == 'L' ? (VALUE) == 0xffff :            \
    (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \
+   (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\
+   (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 32 :        \
    0)
 
 /* Similar, but for floating constants, and defining letters G and H.
@@ -823,7 +948,7 @@ typedef struct i386_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      \
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT)      \
   (init_cumulative_args (&CUM, FNTYPE, LIBNAME))
 
 /* Update the data in CUM to advance over an argument
@@ -856,6 +981,14 @@ typedef struct i386_args {
 #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
   (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
 
+/* This macro is invoked just before the start of a function.
+   It is used here to output code for -fpic that will load the
+   return address into %ebx.  */
+
+#undef ASM_OUTPUT_FUNCTION_PREFIX
+#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \
+  asm_output_function_prefix (FILE, FNNAME)
+
 /* This macro generates the assembly code for function entry.
    FILE is a stdio stream to output the code to.
    SIZE is an int: how many units of temporary storage to allocate.
@@ -885,27 +1018,94 @@ typedef struct i386_args {
     }                                                                  \
 }
 
-/* A C statement or compound statement to output to FILE some
-   assembler code to initialize basic-block profiling for the current
-   object module.  This code should call the subroutine
-   `__bb_init_func' once per object module, passing it as its sole
-   argument the address of a block allocated in the object module.
 
-   The name of the block is a local symbol made with this statement:
+/* There are three profiling modes for basic blocks available.
+   The modes are selected at compile time by using the options
+   -a or -ax of the gnu compiler.
+   The variable `profile_block_flag' will be set according to the
+   selected option.
+
+   profile_block_flag == 0, no option used:
+
+      No profiling done.
+
+   profile_block_flag == 1, -a option used.
+
+      Count frequency of execution of every basic block.
+
+   profile_block_flag == 2, -ax option used.
+
+      Generate code to allow several different profiling modes at run time. 
+      Available modes are:
+             Produce a trace of all basic blocks.
+             Count frequency of jump instructions executed.
+      In every mode it is possible to start profiling upon entering
+      certain functions and to disable profiling of some other functions.
+
+    The result of basic-block profiling will be written to a file `bb.out'.
+    If the -ax option is used parameters for the profiling will be read
+    from file `bb.in'.
+
+*/
+
+/* The following macro shall output assembler code to FILE
+   to initialize basic-block profiling.
+
+   If profile_block_flag == 2
+
+       Output code to call the subroutine `__bb_init_trace_func'
+       and pass two parameters to it. The first parameter is
+       the address of a block allocated in the object module.
+       The second parameter is the number of the first basic block
+       of the function.
 
-       ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+       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.
+       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 first word of this block 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.  */
+       The number of the first basic block of the function is
+       passed to the macro in BLOCK_OR_LABEL.
+
+       If described in a virtual assembler language the code to be
+       output looks like:
+
+               parameter1 <- LPBX0
+               parameter2 <- BLOCK_OR_LABEL
+               call __bb_init_trace_func
+
+    else if profile_block_flag != 0
+
+       Output code to call the subroutine `__bb_init_func'
+       and pass one single parameter to it, which is the same
+       as the first parameter to `__bb_init_trace_func'.
+
+       The first word of this parameter is a flag which will be nonzero if
+       the object module has already been initialized.  So test this word
+       first, and do not call `__bb_init_func' if the flag is nonzero.
+       Note: When profile_block_flag == 2 the test need not be done
+       but `__bb_init_trace_func' *must* be called.
+
+       BLOCK_OR_LABEL may be used to generate a label number as a
+       branch destination in case `__bb_init_func' will not be called.
+
+       If described in a virtual assembler language the code to be
+       output looks like:
+
+               cmp (LPBX0),0
+               jne local_label
+               parameter1 <- LPBX0
+               call __bb_init_func
+local_label:
+
+*/
 
 #undef FUNCTION_BLOCK_PROFILER
-#define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO)                       \
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL)                  \
 do                                                                     \
   {                                                                    \
     static int num_func = 0;                                           \
@@ -913,74 +1113,264 @@ do                                                                      \
     char block_table[80], false_label[80];                             \
                                                                        \
     ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0);              \
-    ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func);       \
                                                                        \
-    xops[0] = const0_rtx;                                              \
     xops[1] = gen_rtx (SYMBOL_REF, VOIDmode, block_table);             \
-    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[5] = stack_pointer_rtx;                                       \
-    xops[6] = GEN_INT (4);                                             \
     xops[7] = gen_rtx (REG, Pmode, 0); /* eax */                       \
                                                                        \
     CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE;                          \
-    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                                                               \
+    switch (profile_block_flag)                                        \
       {                                                                        \
-       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 (STREAM, "LPBZ", num_func);              \
-    num_func++;                                                                \
+      case 2:                                                          \
+                                                                       \
+        xops[2] = GEN_INT ((BLOCK_OR_LABEL));                          \
+        xops[3] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_init_trace_func")); \
+        xops[6] = GEN_INT (8);                                         \
+                                                                       \
+        output_asm_insn (AS1(push%L2,%2), xops);                       \
+        if (!flag_pic)                                                 \
+          output_asm_insn (AS1(push%L1,%1), xops);                     \
+        else                                                           \
+          {                                                            \
+            output_asm_insn (AS2 (lea%L7,%a1,%7), xops);               \
+            output_asm_insn (AS1 (push%L7,%7), xops);                  \
+          }                                                            \
+                                                                       \
+        output_asm_insn (AS1(call,%P3), xops);                         \
+        output_asm_insn (AS2(add%L0,%6,%5), xops);                     \
+                                                                       \
+        break;                                                         \
+                                                                       \
+      default:                                                         \
+                                                                       \
+        ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func);   \
+                                                                       \
+        xops[0] = const0_rtx;                                          \
+        xops[2] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, false_label)); \
+        xops[3] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_init_func")); \
+        xops[4] = gen_rtx (MEM, Pmode, xops[1]);                       \
+        xops[6] = GEN_INT (4);                                         \
+                                                                       \
+        CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE;                      \
+                                                                       \
+        output_asm_insn (AS2(cmp%L4,%0,%4), xops);                     \
+        output_asm_insn (AS1(jne,%2), xops);                           \
+                                                                       \
+        if (!flag_pic)                                                 \
+          output_asm_insn (AS1(push%L1,%1), xops);                     \
+        else                                                           \
+          {                                                            \
+            output_asm_insn (AS2 (lea%L7,%a1,%7), xops);               \
+            output_asm_insn (AS1 (push%L7,%7), xops);                  \
+          }                                                            \
+                                                                       \
+        output_asm_insn (AS1(call,%P3), xops);                         \
+        output_asm_insn (AS2(add%L0,%6,%5), xops);                     \
+        ASM_OUTPUT_INTERNAL_LABEL (FILE, "LPBZ", num_func);            \
+        num_func++;                                                    \
+                                                                       \
+        break;                                                         \
+                                                                       \
+    }                                                                  \
   }                                                                    \
 while (0)
 
+/* The following macro shall output assembler code to FILE
+   to increment a counter associated with basic block number BLOCKNO.
+
+   If profile_block_flag == 2
+
+       Output code to initialize the global structure `__bb' and
+       call the function `__bb_trace_func' which will increment the
+       counter.
+
+       `__bb' consists of two words. In the first word the number
+       of the basic block has to be stored. In the second word
+       the address of a block allocated in the object module 
+       has to be stored.
+
+       The basic block number is given by BLOCKNO.
+
+       The address of the block is given by the label created with 
+
+           ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+       by FUNCTION_BLOCK_PROFILER.
 
-/* A C statement or compound statement to increment the count
-   associated with the basic block number BLOCKNO.  Basic blocks are
-   numbered separately from zero within each compilation.  The count
-   associated with block number BLOCKNO is at index BLOCKNO in a
-   vector of words; the name of this array is a local symbol made
-   with this statement:
+       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.
 
-       ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+       If described in a virtual assembler language the code to be
+       output looks like:
 
-   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.  */
+               move BLOCKNO -> (__bb)
+               move LPBX0 -> (__bb+4)
+               call __bb_trace_func
 
-#define BLOCK_PROFILER(STREAM, BLOCKNO)                                        \
+       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[1], cnt_rtx;                                              \
+    rtx xops[8], cnt_rtx;                                              \
     char counts[80];                                                   \
+    char *block_table = counts;                                                \
+                                                                       \
+    switch (profile_block_flag)                                        \
+      {                                                                        \
                                                                        \
-    ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2);                   \
-    cnt_rtx = gen_rtx (SYMBOL_REF, VOIDmode, counts);                  \
-    SYMBOL_REF_FLAG (cnt_rtx) = TRUE;                                  \
+      case 2:                                                          \
                                                                        \
-    if (BLOCKNO)                                                       \
-      cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4);                  \
+        ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0);          \
                                                                        \
-    if (flag_pic)                                                      \
-      cnt_rtx = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, cnt_rtx);  \
+       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;                       \
                                                                        \
-    xops[0] = gen_rtx (MEM, SImode, cnt_rtx);                          \
-    output_asm_insn (AS1(inc%L0,%0), xops);                            \
+       fprintf(FILE, "\tpushf\n");                                     \
+        output_asm_insn (AS2(mov%L0,%2,%0), xops);                     \
+       if (flag_pic)                                                   \
+         {                                                             \
+            xops[7] = gen_rtx (REG, Pmode, 0); /* eax */               \
+            output_asm_insn (AS1(push%L7,%7), xops);                   \
+            output_asm_insn (AS2(lea%L7,%a1,%7), xops);                        \
+            output_asm_insn (AS2(mov%L6,%7,%6), xops);                 \
+            output_asm_insn (AS1(pop%L7,%7), xops);                    \
+         }                                                             \
+        else                                                           \
+          output_asm_insn (AS2(mov%L6,%1,%6), xops);                   \
+        output_asm_insn (AS1(call,%P3), xops);                         \
+       fprintf(FILE, "\tpopf\n");                                      \
+                                                                       \
+        break;                                                         \
+                                                                       \
+      default:                                                         \
+                                                                       \
+        ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2);               \
+        cnt_rtx = gen_rtx (SYMBOL_REF, VOIDmode, counts);              \
+        SYMBOL_REF_FLAG (cnt_rtx) = TRUE;                              \
+                                                                       \
+        if (BLOCKNO)                                                   \
+          cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4);              \
+                                                                       \
+        if (flag_pic)                                                  \
+          cnt_rtx = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, cnt_rtx);      \
+                                                                       \
+        xops[0] = gen_rtx (MEM, SImode, cnt_rtx);                      \
+        output_asm_insn (AS1(inc%L0,%0), xops);                                \
+                                                                       \
+        break;                                                         \
+                                                                       \
+    }                                                                  \
   }                                                                    \
 while (0)
 
+/* The following macro shall output assembler code to FILE
+   to indicate a return from function during basic-block profiling.
+
+   If profiling_block_flag == 2:
+
+       Output assembler code to call function `__bb_trace_ret'.
+
+       Note that function `__bb_trace_ret' must not change the
+       machine state, especially the flag register. To grant
+       this, you must output code to save and restore registers
+       either in this macro or in the macros MACHINE_STATE_SAVE_RET
+       and MACHINE_STATE_RESTORE_RET. The last two macros will be
+       used in the function `__bb_trace_ret', so you must make
+       sure that the function prologue does not change any 
+       register prior to saving it with MACHINE_STATE_SAVE_RET.
+
+   else if profiling_block_flag != 0:
+
+       The macro will not be used, so it need not distinguish
+       these cases.
+*/
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
+do                                                                     \
+  {                                                                    \
+    rtx xops[1];                                                       \
+                                                                       \
+    xops[0] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_trace_ret")); \
+                                                                       \
+    output_asm_insn (AS1(call,%P0), xops);                             \
+                                                                       \
+  }                                                                    \
+while (0)
+
+/* The function `__bb_trace_func' is called in every basic block
+   and is not allowed to change the machine state. Saving (restoring)
+   the state can either be done in the BLOCK_PROFILER macro,
+   before calling function (rsp. after returning from function)
+   `__bb_trace_func', or it can be done inside the function by
+   defining the macros:
+
+       MACHINE_STATE_SAVE(ID)
+       MACHINE_STATE_RESTORE(ID)
+
+   In the latter case care must be taken, that the prologue code
+   of function `__bb_trace_func' does not already change the
+   state prior to saving it with MACHINE_STATE_SAVE.
+
+   The parameter `ID' is a string identifying a unique macro use.
+
+   On the i386 the initialization code at the begin of
+   function `__bb_trace_func' contains a `sub' instruction
+   therefore we handle save and restore of the flag register 
+   in the BLOCK_PROFILER macro. */
+
+#define MACHINE_STATE_SAVE(ID) \
+  asm ("       pushl %eax"); \
+  asm ("       pushl %ecx"); \
+  asm ("       pushl %edx"); \
+  asm ("       pushl %esi");
+
+#define MACHINE_STATE_RESTORE(ID) \
+  asm ("       popl %esi"); \
+  asm ("       popl %edx"); \
+  asm ("       popl %ecx"); \
+  asm ("       popl %eax");
+
 /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
    the stack pointer does not matter.  The value is tested only in
    functions that have frame pointers.
@@ -1006,14 +1396,19 @@ while (0)
    off the end.  This happens if the function ends in an "exit" call, or
    if a `return' insn is emitted directly into the function. */
 
-#define FUNCTION_EPILOGUE(FILE, SIZE)          \
+#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);            \
+/*  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.  */
@@ -1243,6 +1638,8 @@ do {                                              \
     goto WIN;                                                          \
 }
 
+#define REWRITE_ADDRESS(x) rewrite_address(x)
+
 /* Nonzero if the constant value X is a legitimate general operand
    when generating PIC code.  It is given that flag_pic is on and 
    that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
@@ -1277,6 +1674,15 @@ do                                                                       \
       {                                                                        \
        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 = %s\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));                                  \
@@ -1367,22 +1773,23 @@ while (0)
    in one reasonably fast instruction.  */
 #define MOVE_MAX 4
 
-/* MOVE_RATIO is the number of move instructions that is better than a
-   block move.  Make this large on i386, since the block move is very
-   inefficient with small blocks, and the hard register needs of the
-   block move require much reload work. */
-#define MOVE_RATIO 5
+/* The number of scalar move insns which should be generated instead
+   of a string move insn or a library call.  Increasing the value
+   will always make code faster, but eventually incurs high cost in
+   increased code size.
 
-/* Define this if zero-extension is slow (more than one real instruction).  */
-/* #define SLOW_ZERO_EXTEND */
+   If you don't define this, a reasonable default is used.
 
-/* Nonzero if access to memory by bytes is slow and undesirable.  */
-#define SLOW_BYTE_ACCESS 0
+   Make this large on i386, since the block move is very inefficient with small
+   blocks, and the hard register needs of the block move require much reload
+   work. */
+
+#define MOVE_RATIO 5
 
 /* Define if shifts truncate the shift count
    which implies one can omit a sign-extension or zero-extension
    of a shift count.  */
-/* One 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 */
 
@@ -1409,70 +1816,192 @@ while (0)
    is a byte address (for indexing purposes)
    so give the MEM rtx a byte's mode.  */
 #define FUNCTION_MODE QImode
-
-/* Define this if addresses of constant functions
-   shouldn't be put through pseudo regs where they can be cse'd.
-   Desirable on the 386 because a CALL with a constant address is
-   not much slower than one with a register address.  On a 486,
-   it is faster to call with a constant address than indirect.  */
-#define NO_FUNCTION_CSE
-
-/* Provide the costs of a rtl expression.  This is in the body of a
-   switch on CODE. */
-
-#define RTX_COSTS(X,CODE,OUTER_CODE)                           \
-  case MULT:                                                   \
-    return COSTS_N_INSNS (20);                                 \
-  case DIV:                                                    \
-  case UDIV:                                                   \
-  case MOD:                                                    \
-  case UMOD:                                                   \
-    return COSTS_N_INSNS (20);                                 \
-  case ASHIFTRT:                                               \
-  case LSHIFTRT:                                               \
-  case ASHIFT:                                                 \
-    return (4 + rtx_cost (XEXP (X, 0), OUTER_CODE)             \
-           + rtx_cost (XEXP (X, 1), OUTER_CODE));              \
-  case PLUS:                                                   \
-    if (GET_CODE (XEXP (X, 0)) == MULT                         \
-       && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT        \
-       && (INTVAL (XEXP (XEXP (X, 0), 1)) == 2                 \
-           || INTVAL (XEXP (XEXP (X, 0), 1)) == 4              \
-           || INTVAL (XEXP (XEXP (X, 0), 1)) == 8))            \
-      return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
-             + rtx_cost (XEXP (X, 1), OUTER_CODE));            \
-    break;
-
-
-/* Compute the cost of computing a constant rtl expression RTX
-   whose rtx-code is CODE.  The body of this macro is a portion
-   of a switch statement.  If the code is computed here,
-   return it with a return statement.  Otherwise, break from the switch.  */
+\f
+/* A part of a C `switch' statement that describes the relative costs
+   of constant RTL expressions.  It must contain `case' labels for
+   expression codes `const_int', `const', `symbol_ref', `label_ref'
+   and `const_double'.  Each case must ultimately reach a `return'
+   statement to return the relative cost of the use of that kind of
+   constant value in an expression.  The cost may depend on the
+   precise value of the constant, which is available for examination
+   in X, and the rtx code of the expression in which it is contained,
+   found in OUTER_CODE.
+  
+   CODE is the expression code--redundant, since it can be obtained
+   with `GET_CODE (X)'.  */
 
 #define CONST_COSTS(RTX,CODE,OUTER_CODE) \
   case CONST_INT:                                              \
   case CONST:                                                  \
   case LABEL_REF:                                              \
   case SYMBOL_REF:                                             \
-    return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 0;           \
+    return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 1;           \
+                                                               \
   case CONST_DOUBLE:                                           \
     {                                                          \
       int code;                                                        \
       if (GET_MODE (RTX) == VOIDmode)                          \
        return 2;                                               \
+                                                               \
       code = standard_80387_constant_p (RTX);                  \
       return code == 1 ? 0 :                                   \
             code == 2 ? 1 :                                    \
                         2;                                     \
     }
 
-/* Compute the cost of an address.  This is meant to approximate the size
-   and/or execution delay of an insn using that address.  If the cost is
-   approximated by the RTL complexity, including CONST_COSTS above, as
-   is usually the case for CISC machines, this macro should not be defined.
-   For aggressively RISCy machines, only one insn format is allowed, so
-   this macro should be a constant.  The value of this macro only matters
-   for valid addresses.
+/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
+#define TOPLEVEL_COSTS_N_INSNS(N) {total = COSTS_N_INSNS (N); break;}
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+   This can be used, for example, to indicate how costly a multiply
+   instruction is.  In writing this macro, you can use the construct
+   `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+   instructions.  OUTER_CODE is the code of the expression in which X
+   is contained.
+
+   This macro is optional; do not define it if the default cost
+   assumptions are adequate for the target machine.  */
+
+#define RTX_COSTS(X,CODE,OUTER_CODE)                                   \
+  case ASHIFT:                                                         \
+    if (GET_CODE (XEXP (X, 1)) == CONST_INT                            \
+       && GET_MODE (XEXP (X, 0)) == SImode)                            \
+      {                                                                        \
+       HOST_WIDE_INT value = INTVAL (XEXP (X, 1));                     \
+                                                                       \
+       if (value == 1)                                                 \
+         return COSTS_N_INSNS (ix86_cost->add)                         \
+                               + rtx_cost(XEXP (X, 0), OUTER_CODE);    \
+                                                                       \
+       if (value == 2 || value == 3)                                   \
+         return COSTS_N_INSNS (ix86_cost->lea)                         \
+                                + rtx_cost(XEXP (X, 0), OUTER_CODE);   \
+      }                                                                        \
+    /* fall through */                                                 \
+                                                                       \
+  case ROTATE:                                                         \
+  case ASHIFTRT:                                                       \
+  case LSHIFTRT:                                                       \
+  case ROTATERT:                                                       \
+    if (GET_MODE (XEXP (X, 0)) == DImode)                              \
+      {                                                                        \
+       if (GET_CODE (XEXP (X, 1)) == CONST_INT)                        \
+         if (INTVAL (XEXP (X, 1)) > 32)                                        \
+           return COSTS_N_INSNS(ix86_cost->shift_const + 2);           \
+         else                                                          \
+           return COSTS_N_INSNS(ix86_cost->shift_const * 2);           \
+       return ((GET_CODE (XEXP (X, 1)) == AND                          \
+                ? COSTS_N_INSNS(ix86_cost->shift_var * 2)              \
+                : COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2))         \
+               + rtx_cost(XEXP (X, 0), OUTER_CODE));                   \
+      }                                                                        \
+    return COSTS_N_INSNS (GET_CODE (XEXP (X, 1)) == CONST_INT          \
+                         ? ix86_cost->shift_const                      \
+                         : ix86_cost->shift_var)                       \
+      + rtx_cost(XEXP (X, 0), OUTER_CODE);                             \
+                                                                       \
+  case MULT:                                                           \
+    if (GET_CODE (XEXP (X, 1)) == CONST_INT)                           \
+      {                                                                        \
+       unsigned HOST_WIDE_INT value = INTVAL (XEXP (X, 1));            \
+       int nbits = 0;                                                  \
+                                                                       \
+       if (value == 2)                                                 \
+         return COSTS_N_INSNS (ix86_cost->add)                         \
+                                + rtx_cost(XEXP (X, 0), OUTER_CODE);   \
+       if (value == 4 || value == 8)                                   \
+         return COSTS_N_INSNS (ix86_cost->lea)                         \
+                                + rtx_cost(XEXP (X, 0), OUTER_CODE);   \
+                                                                       \
+       while (value != 0)                                              \
+         {                                                             \
+           nbits++;                                                    \
+           value >>= 1;                                                \
+         }                                                             \
+                                                                       \
+       if (nbits == 1)                                                 \
+         return COSTS_N_INSNS (ix86_cost->shift_const)                 \
+           + rtx_cost(XEXP (X, 0), OUTER_CODE);                        \
+                                                                       \
+       return COSTS_N_INSNS (ix86_cost->mult_init                      \
+                             + nbits * ix86_cost->mult_bit)            \
+         + rtx_cost(XEXP (X, 0), OUTER_CODE);                          \
+      }                                                                        \
+                                                                       \
+    else                       /* This is arbitrary */                 \
+      TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init                     \
+                             + 7 * ix86_cost->mult_bit);               \
+                                                                       \
+  case DIV:                                                            \
+  case UDIV:                                                           \
+  case MOD:                                                            \
+  case UMOD:                                                           \
+    TOPLEVEL_COSTS_N_INSNS (ix86_cost->divide);                                \
+                                                                       \
+  case PLUS:                                                           \
+    if (GET_CODE (XEXP (X, 0)) == REG                                  \
+       && GET_MODE (XEXP (X, 0)) == SImode                             \
+       && GET_CODE (XEXP (X, 1)) == PLUS)                              \
+      return COSTS_N_INSNS (ix86_cost->lea);                           \
+                                                                       \
+    /* fall through */                                                 \
+  case AND:                                                            \
+  case IOR:                                                            \
+  case XOR:                                                            \
+  case MINUS:                                                          \
+    if (GET_MODE (X) == DImode)                                                \
+      return COSTS_N_INSNS (ix86_cost->add) * 2                                \
+       + (rtx_cost (XEXP (X, 0), OUTER_CODE)                           \
+          << (GET_MODE (XEXP (X, 0)) != DImode))                       \
+       + (rtx_cost (XEXP (X, 1), OUTER_CODE)                           \
+          << (GET_MODE (XEXP (X, 1)) != DImode));                      \
+  case NEG:                                                            \
+  case NOT:                                                            \
+    if (GET_MODE (X) == DImode)                                                \
+      TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2)                      \
+    TOPLEVEL_COSTS_N_INSNS (ix86_cost->add)
+
+
+/* An expression giving the cost of an addressing mode that contains
+   ADDRESS.  If not defined, the cost is computed from the ADDRESS
+   expression and the `CONST_COSTS' values.
+
+   For most CISC machines, the default cost is a good approximation
+   of the true cost of the addressing mode.  However, on RISC
+   machines, all instructions normally have the same length and
+   execution time.  Hence all addresses will have equal costs.
+
+   In cases where more than one form of an address is known, the form
+   with the lowest cost will be used.  If multiple forms have the
+   same, lowest, cost, the one that is the most complex will be used.
+
+   For example, suppose an address that is equal to the sum of a
+   register and a constant is used twice in the same basic block.
+   When this macro is not defined, the address will be computed in a
+   register and memory references will be indirect through that
+   register.  On machines where the cost of the addressing mode
+   containing the sum is no higher than that of a simple indirect
+   reference, this will produce an additional instruction and
+   possibly require an additional register.  Proper specification of
+   this macro eliminates this overhead for such machines.
+
+   Similar use of this macro is made in strength reduction of loops.
+
+   ADDRESS need not be valid as an address.  In such a case, the cost
+   is not relevant and can be any value; invalid addresses need not be
+   assigned a different cost.
+
+   On machines where an address involving more than one register is as
+   cheap as an address computation involving only one register,
+   defining `ADDRESS_COST' to reflect this can cause two registers to
+   be live over a region of code where only one would have been if
+   `ADDRESS_COST' were not defined in that manner.  This effect should
+   be considered in the definition of this macro.  Equivalent costs
+   should probably only be given to addresses with different numbers
+   of registers on machines with lots of registers.
+
+   This macro will normally either not be defined or be defined as a
+   constant.
 
    For i386, it is better to use a complex address than let gcc copy
    the address into a reg and make a new pseudo.  But not if the address
@@ -1485,6 +2014,193 @@ while (0)
        && REG_P (XEXP (RTX, 0)))) ? 0                          \
    : REG_P (RTX) ? 1                                           \
    : 2)
+
+/* A C expression for the cost of moving data of mode M between a
+   register and memory.  A value of 2 is the default; this cost is
+   relative to those in `REGISTER_MOVE_COST'.
+
+   If moving between registers and memory is more expensive than
+   between two registers, you should define this macro to express the
+   relative cost.
+
+   On the i386, copying between floating-point and fixed-point
+   registers is expensive.  */
+
+#define REGISTER_MOVE_COST(CLASS1, CLASS2)                             \
+  (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2))               \
+    || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10      \
+   : 2)
+
+
+/* A C expression for the cost of moving data of mode M between a
+   register and memory.  A value of 2 is the default; this cost is
+   relative to those in `REGISTER_MOVE_COST'.
+
+   If moving between registers and memory is more expensive than
+   between two registers, you should define this macro to express the
+   relative cost.  */
+
+/* #define MEMORY_MOVE_COST(M) 2  */
+
+/* A C expression for the cost of a branch instruction.  A value of 1
+   is the default; other values are interpreted relative to that.  */
+
+#define BRANCH_COST i386_branch_cost
+
+/* Define this macro as a C expression which is nonzero if accessing
+   less than a word of memory (i.e. a `char' or a `short') is no
+   faster than accessing a word of memory, i.e., if such access
+   require more than one instruction or if there is no difference in
+   cost between byte and (aligned) word loads.
+
+   When this macro is not defined, the compiler will access a field by
+   finding the smallest containing object; when it is defined, a
+   fullword load will be used if alignment permits.  Unless bytes
+   accesses are faster than word accesses, using word accesses is
+   preferable since it may eliminate subsequent memory access if
+   subsequent accesses occur to other fields in the same word of the
+   structure, but to different bytes.  */
+
+#define SLOW_BYTE_ACCESS 0
+
+/* Nonzero if access to memory by shorts is slow and undesirable.  */
+#define SLOW_SHORT_ACCESS 0
+
+/* Define this macro if zero-extension (of a `char' or `short' to an
+   `int') can be done faster if the destination is a register that is
+   known to be zero.
+
+   If you define this macro, you must have instruction patterns that
+   recognize RTL structures like this:
+
+          (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+   and likewise for `HImode'.  */
+
+/* #define SLOW_ZERO_EXTEND */
+
+/* Define this macro to be the value 1 if unaligned accesses have a
+   cost many times greater than aligned accesses, for example if they
+   are emulated in a trap handler.
+
+   When this macro is non-zero, the compiler will act as if
+   `STRICT_ALIGNMENT' were non-zero when generating code for block
+   moves.  This can cause significantly more instructions to be
+   produced.  Therefore, do not set this macro non-zero if unaligned
+   accesses only add a cycle or two to the time for a memory access.
+
+   If the value of this macro is always zero, it need not be defined.  */
+
+/* #define SLOW_UNALIGNED_ACCESS 0 */
+
+/* Define this macro to inhibit strength reduction of memory
+   addresses.  (On some machines, such strength reduction seems to do
+   harm rather than good.)  */
+
+/* #define DONT_REDUCE_ADDR */
+
+/* Define this macro if it is as good or better to call a constant
+   function address than to call an address kept in a register.
+
+   Desirable on the 386 because a CALL with a constant address is
+   faster than one with a register address.  */
+
+#define NO_FUNCTION_CSE
+
+/* Define this macro if it is as good or better for a function to call
+   itself with an explicit address than to call an address kept in a
+   register.  */
+
+#define NO_RECURSIVE_FUNCTION_CSE
+
+/* A C statement (sans semicolon) to update the integer variable COST
+   based on the relationship between INSN that is dependent on
+   DEP_INSN through the dependence LINK.  The default is to make no
+   adjustment to COST.  This can be used for example to specify to
+   the scheduler that an output- or anti-dependence does not incur
+   the same cost as a data-dependence.  */
+
+#define ADJUST_COST(insn,link,dep_insn,cost)                           \
+  {                                                                    \
+    rtx next_inst;                                                     \
+    if (GET_CODE (dep_insn) == CALL_INSN)                              \
+      (cost) = 0;                                                      \
+                                                                       \
+    else 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))))         \
+      {                                                                        \
+       (cost) = 0;                                                     \
+      }                                                                        \
+                                                                       \
+    else if (GET_CODE (insn) == JUMP_INSN)                             \
+      {                                                                        \
+        (cost) = 0;                                                    \
+      }                                                                        \
+                                                                       \
+    if (TARGET_PENTIUM)                                                        \
+      {                                                                        \
+        if (cost !=0 && is_fp_insn (insn) && is_fp_insn (dep_insn)     \
+            && !is_fp_dest (dep_insn))                                 \
+          {                                                            \
+            (cost) = 0;                                                        \
+          }                                                            \
+                                                                       \
+        if (agi_dependent (insn, dep_insn))                            \
+          {                                                            \
+            (cost) = 3;                                                        \
+          }                                                            \
+        else 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 */                    \
+            (cost) = 0;                                                        \
+          }                                                            \
+      }                                                                        \
+    else                                                               \
+      if (!is_fp_dest (dep_insn))                                      \
+       {                                                               \
+         if(!agi_dependent (insn, dep_insn))                           \
+           (cost) = 0;                                                 \
+         else if (TARGET_486)                                          \
+           (cost) = 2;                                                 \
+       }                                                               \
+      else                                                             \
+       if (is_fp_store (insn) && is_fp_insn (dep_insn)                 \
+           && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn))         \
+           && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))                 \
+           && (GET_CODE (NEXT_INSN (insn)) == INSN)                    \
+           && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN)   \
+           && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE) \
+           && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) \
+               == NOTE_INSN_LOOP_END))                                 \
+         {                                                             \
+           (cost) = 3;                                                 \
+         }                                                             \
+  }
+
+
+#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;                                                  \
+    }                                                                  \
+}
+
 \f
 /* Add any extra modes needed to represent the condition code.
 
@@ -1517,6 +2233,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
 /* 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
@@ -1525,6 +2245,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
    the state of equality is indicated by zero in the carry bit.  */
 #define CC_Z_IN_NOT_C 010000
 
+/* Set if the CC value was actually from the 80387 and loaded directly
+   into the eflags instead of via eax/sahf.  */
+#define CC_FCOMI 040000
+
 /* Store in cc_status the expressions
    that the condition codes will describe
    after execution of an instruction whose pattern is EXP.
@@ -1855,9 +2579,24 @@ extern char *qi_high_reg_name[];
 #define RET return ""
 #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
 \f
+/* Helper macros to expand a binary/unary operator if needed */
+#define IX86_EXPAND_BINARY_OPERATOR(OP, MODE, OPERANDS)                        \
+do {                                                                   \
+  if (!ix86_expand_binary_operator (OP, MODE, OPERANDS))               \
+    FAIL;                                                              \
+} while (0)
+
+#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS)                 \
+do {                                                                   \
+  if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,))               \
+    FAIL;                                                              \
+} while (0)
+
+\f
 /* Functions in i386.c */
 extern void override_options ();
 extern void order_regs_for_local_alloc ();
+extern char *output_strlen_unroll ();
 extern int i386_valid_decl_attribute_p ();
 extern int i386_valid_type_attribute_p ();
 extern int i386_return_pops_args ();
@@ -1866,6 +2605,7 @@ 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 void output_op_from_reg ();
 extern void output_to_reg ();
 extern char *singlemove_string ();
@@ -1878,6 +2618,10 @@ 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 ();
@@ -1900,17 +2644,37 @@ 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 ();
+
+#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_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_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) */
@@ -1919,11 +2683,12 @@ 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 */
+extern int optimize;                           /* optimization level */
+extern int obey_regdecls;                      /* TRUE if stupid register allocation */
 
 /* External functions used */
 extern struct rtx_def *force_operand ();
+
 \f
 /*
 Local variables: