OSDN Git Service

(override_options): Set default for -mcpu to PROCESSOR_DEFAULT_STRING.
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
1 /* Subroutines for insn-output.c for Intel X86.
2    Copyright (C) 1988, 1992, 1994, 1995, 1996 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <stdio.h>
22 #include <setjmp.h>
23 #include <ctype.h>
24 #include "config.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "tree.h"
35 #include "flags.h"
36 #include "except.h"
37 #include "function.h"
38
39 #ifdef EXTRA_CONSTRAINT
40 /* If EXTRA_CONSTRAINT is defined, then the 'S'
41    constraint in REG_CLASS_FROM_LETTER will no longer work, and various
42    asm statements that need 'S' for class SIREG will break.  */
43  error EXTRA_CONSTRAINT conflicts with S constraint letter
44 /* The previous line used to be #error, but some compilers barf
45    even if the conditional was untrue.  */
46 #endif
47
48 #ifndef CHECK_STACK_LIMIT
49 #define CHECK_STACK_LIMIT -1
50 #endif
51
52 enum reg_mem                    /* Type of an operand for ix86_{binary,unary}_operator_ok */
53 {
54   reg_p,
55   mem_p,
56   imm_p
57 };
58
59 /* Processor costs (relative to an add) */
60 struct processor_costs i386_cost = {    /* 386 specific costs */
61   1,                                    /* cost of an add instruction (2 cycles) */
62   1,                                    /* cost of a lea instruction */
63   3,                                    /* variable shift costs */
64   2,                                    /* constant shift costs */
65   6,                                    /* cost of starting a multiply */
66   1,                                    /* cost of multiply per each bit set */
67   23                                    /* cost of a divide/mod */
68 };
69
70 struct processor_costs i486_cost = {    /* 486 specific costs */
71   1,                                    /* cost of an add instruction */
72   1,                                    /* cost of a lea instruction */
73   3,                                    /* variable shift costs */
74   2,                                    /* constant shift costs */
75   12,                                   /* cost of starting a multiply */
76   1,                                    /* cost of multiply per each bit set */
77   40                                    /* cost of a divide/mod */
78 };
79
80 struct processor_costs pentium_cost = {
81   1,                                    /* cost of an add instruction */
82   1,                                    /* cost of a lea instruction */
83   3,                                    /* variable shift costs */
84   1,                                    /* constant shift costs */
85   12,                                   /* cost of starting a multiply */
86   1,                                    /* cost of multiply per each bit set */
87   25                                    /* cost of a divide/mod */
88 };
89
90 struct processor_costs *ix86_cost = &pentium_cost;
91
92 #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
93
94 extern FILE *asm_out_file;
95 extern char *strcat ();
96
97 char *singlemove_string ();
98 char *output_move_const_single ();
99 char *output_fp_cc0_set ();
100
101 char *hi_reg_name[] = HI_REGISTER_NAMES;
102 char *qi_reg_name[] = QI_REGISTER_NAMES;
103 char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
104
105 /* Array of the smallest class containing reg number REGNO, indexed by
106    REGNO.  Used by REGNO_REG_CLASS in i386.h. */
107
108 enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
109 {
110   /* ax, dx, cx, bx */
111   AREG, DREG, CREG, BREG,
112   /* si, di, bp, sp */
113   SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
114   /* FP registers */
115   FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
116   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,       
117   /* arg pointer */
118   INDEX_REGS
119 };
120
121 /* Test and compare insns in i386.md store the information needed to
122    generate branch and scc insns here.  */
123
124 struct rtx_def *i386_compare_op0 = NULL_RTX;
125 struct rtx_def *i386_compare_op1 = NULL_RTX;
126 struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
127
128 /* which cpu are we scheduling for */
129 enum processor_type ix86_cpu;
130
131 /* which instruction set architecture to use.  */
132 int ix86_arch;
133
134 /* Strings to hold which cpu and instruction set architecture  to use.  */
135 char *ix86_cpu_string;          /* for -mcpu=<xxx> */
136 char *ix86_arch_string;         /* for -march=<xxx> */
137
138 /* Register allocation order */
139 char *i386_reg_alloc_order;
140 static char regs_allocated[FIRST_PSEUDO_REGISTER];
141
142 /* # of registers to use to pass arguments. */
143 char *i386_regparm_string;                      /* # registers to use to pass args */
144 int i386_regparm;                               /* i386_regparm_string as a number */
145
146 /* Alignment to use for loops and jumps */
147 char *i386_align_loops_string;                  /* power of two alignment for loops */
148 char *i386_align_jumps_string;                  /* power of two alignment for non-loop jumps */
149 char *i386_align_funcs_string;                  /* power of two alignment for functions */
150 char *i386_branch_cost_string;                  /* values 1-5: see jump.c */
151
152 int i386_align_loops;                           /* power of two alignment for loops */
153 int i386_align_jumps;                           /* power of two alignment for non-loop jumps */
154 int i386_align_funcs;                           /* power of two alignment for functions */
155 int i386_branch_cost;                           /* values 1-5: see jump.c */
156
157 /* Sometimes certain combinations of command options do not make
158    sense on a particular target machine.  You can define a macro
159    `OVERRIDE_OPTIONS' to take account of this.  This macro, if
160    defined, is executed once just after all the command options have
161    been parsed.
162
163    Don't use this macro to turn on various extra optimizations for
164    `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
165
166 void
167 override_options ()
168 {
169   int ch, i, j, regno;
170   char *p;
171   int def_align;
172
173   static struct ptt
174     {
175       char *name;               /* Canonical processor name.  */
176       enum processor_type processor; /* Processor type enum value.  */
177       struct processor_costs *cost; /* Processor costs */
178       int target_enable;        /* Target flags to enable.  */
179       int target_disable;       /* Target flags to disable.  */
180     } processor_target_table[]
181       = {{PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},
182            {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},
183            {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
184            {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
185            {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentium_cost, 0, 0},
186            {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO, &pentium_cost, 0, 0}};
187
188   int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
189
190 #ifdef SUBTARGET_OVERRIDE_OPTIONS
191   SUBTARGET_OVERRIDE_OPTIONS;
192 #endif
193
194   /* Validate registers in register allocation order */
195   if (i386_reg_alloc_order)
196     {
197       for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
198         {
199           switch (ch)
200             {
201             case 'a':   regno = 0;      break;
202             case 'd':   regno = 1;      break;
203             case 'c':   regno = 2;      break;
204             case 'b':   regno = 3;      break;
205             case 'S':   regno = 4;      break;
206             case 'D':   regno = 5;      break;
207             case 'B':   regno = 6;      break;
208
209             default:    fatal ("Register '%c' is unknown", ch);
210             }
211
212           if (regs_allocated[regno])
213             fatal ("Register '%c' was already specified in the allocation order", ch);
214
215           regs_allocated[regno] = 1;
216         }
217     }
218
219   if (ix86_arch_string == (char *)0)
220     {
221       ix86_arch_string = PROCESSOR_PENTIUM_STRING;
222       if (ix86_cpu_string == (char *)0)
223         ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
224     }
225   
226   for (i = 0; i < ptt_size; i++)
227     if (! strcmp (ix86_arch_string, processor_target_table[i].name))
228       {
229         ix86_arch = processor_target_table[i].processor;
230         if (ix86_cpu_string == (char *)0)
231           ix86_cpu_string = processor_target_table[i].name;
232         break;
233       }
234
235   if (i == ptt_size)
236     {
237       error ("bad value (%s) for -march= switch", ix86_arch_string);
238       ix86_arch_string = PROCESSOR_PENTIUM_STRING;
239       ix86_arch = PROCESSOR_DEFAULT;
240     }
241
242   if (ix86_cpu_string == (char *)0)
243       ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
244
245   for (j = 0; j < ptt_size; j++)
246     if (! strcmp (ix86_cpu_string, processor_target_table[j].name))
247       {
248         ix86_cpu = processor_target_table[j].processor;
249         if (i > j && (int)ix86_arch >= (int)PROCESSOR_PENTIUMPRO)
250           error ("-mcpu=%s does not support -march=%s", ix86_cpu_string, ix86_arch_string);
251
252         target_flags |= processor_target_table[j].target_enable;
253         target_flags &= ~processor_target_table[j].target_disable;
254         break;
255       }
256
257   if (j == ptt_size)
258     {
259       error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
260       ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
261       ix86_cpu = PROCESSOR_DEFAULT;
262     }
263   /* Validate -mregparm= value */
264   if (i386_regparm_string)
265     {
266       i386_regparm = atoi (i386_regparm_string);
267       if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)
268         fatal ("-mregparm=%d is not between 0 and %d", i386_regparm, REGPARM_MAX);
269     }
270
271   def_align = (TARGET_386) ? 2 : 4;
272
273   /* Validate -malign-loops= value, or provide default */
274   if (i386_align_loops_string)
275     {
276       i386_align_loops = atoi (i386_align_loops_string);
277       if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN)
278         fatal ("-malign-loops=%d is not between 0 and %d",
279                i386_align_loops, MAX_CODE_ALIGN);
280     }
281   else
282     i386_align_loops = 2;
283
284   /* Validate -malign-jumps= value, or provide default */
285   if (i386_align_jumps_string)
286     {
287       i386_align_jumps = atoi (i386_align_jumps_string);
288       if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN)
289         fatal ("-malign-jumps=%d is not between 0 and %d",
290                i386_align_jumps, MAX_CODE_ALIGN);
291     }
292   else
293     i386_align_jumps = def_align;
294
295   /* Validate -malign-functions= value, or provide default */
296   if (i386_align_funcs_string)
297     {
298       i386_align_funcs = atoi (i386_align_funcs_string);
299       if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN)
300         fatal ("-malign-functions=%d is not between 0 and %d",
301                i386_align_funcs, MAX_CODE_ALIGN);
302     }
303   else
304     i386_align_funcs = def_align;
305
306   /* Validate -mbranch-cost= value, or provide default */
307   if (i386_branch_cost_string)
308     {
309       i386_branch_cost = atoi (i386_branch_cost_string);
310       if (i386_branch_cost < 0 || i386_branch_cost > 5)
311         fatal ("-mbranch-cost=%d is not between 0 and 5",
312                i386_branch_cost);
313     }
314   else
315     i386_branch_cost = 1;
316
317   if (TARGET_OMIT_LEAF_FRAME_POINTER)   /* keep nonleaf frame pointers */
318     flag_omit_frame_pointer = 1;
319
320   /* pic references don't explicitly mention pic_offset_table_rtx */
321   /* code threaded into the prologue may conflict with profiling */
322   if (flag_pic || profile_flag || profile_block_flag)
323     target_flags &= ~MASK_SCHEDULE_PROLOGUE;
324 }
325 \f
326 /* A C statement (sans semicolon) to choose the order in which to
327    allocate hard registers for pseudo-registers local to a basic
328    block.
329
330    Store the desired register order in the array `reg_alloc_order'.
331    Element 0 should be the register to allocate first; element 1, the
332    next register; and so on.
333
334    The macro body should not assume anything about the contents of
335    `reg_alloc_order' before execution of the macro.
336
337    On most machines, it is not necessary to define this macro.  */
338
339 void
340 order_regs_for_local_alloc ()
341 {
342   int i, ch, order, regno;
343
344   /* User specified the register allocation order */
345   if (i386_reg_alloc_order)
346     {
347       for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
348         {
349           switch (ch)
350             {
351             case 'a':   regno = 0;      break;
352             case 'd':   regno = 1;      break;
353             case 'c':   regno = 2;      break;
354             case 'b':   regno = 3;      break;
355             case 'S':   regno = 4;      break;
356             case 'D':   regno = 5;      break;
357             case 'B':   regno = 6;      break;
358             }
359
360           reg_alloc_order[order++] = regno;
361         }
362
363       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
364         {
365           if (!regs_allocated[i])
366             reg_alloc_order[order++] = i;
367         }
368     }
369
370   /* If users did not specify a register allocation order, use natural order */
371   else
372     {
373       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
374         reg_alloc_order[i] = i;
375     }
376 }
377
378 \f
379 void
380 optimization_options (level)
381      int level;
382 {
383   /* For -O2, and beyond, turn off -fschedule-insns by default.  It tends to
384      make the problem with not enough registers even worse */
385 #ifdef INSN_SCHEDULING
386   if (level > 1)
387     flag_schedule_insns = 0;
388 #endif
389 }
390 \f
391 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
392    attribute for DECL.  The attributes in ATTRIBUTES have previously been
393    assigned to DECL.  */
394
395 int
396 i386_valid_decl_attribute_p (decl, attributes, identifier, args)
397      tree decl;
398      tree attributes;
399      tree identifier;
400      tree args;
401 {
402   return 0;
403 }
404
405 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
406    attribute for TYPE.  The attributes in ATTRIBUTES have previously been
407    assigned to TYPE.  */
408
409 int
410 i386_valid_type_attribute_p (type, attributes, identifier, args)
411      tree type;
412      tree attributes;
413      tree identifier;
414      tree args;
415 {
416   if (TREE_CODE (type) != FUNCTION_TYPE
417       && TREE_CODE (type) != FIELD_DECL
418       && TREE_CODE (type) != TYPE_DECL)
419     return 0;
420
421   /* Stdcall attribute says callee is responsible for popping arguments
422      if they are not variable.  */
423   if (is_attribute_p ("stdcall", identifier))
424     return (args == NULL_TREE);
425
426   /* Cdecl attribute says the callee is a normal C declaration */
427   if (is_attribute_p ("cdecl", identifier))
428     return (args == NULL_TREE);
429
430   /* Regparm attribute specifies how many integer arguments are to be
431      passed in registers */
432   if (is_attribute_p ("regparm", identifier))
433     {
434       tree cst;
435
436       if (!args || TREE_CODE (args) != TREE_LIST
437           || TREE_CHAIN (args) != NULL_TREE
438           || TREE_VALUE (args) == NULL_TREE)
439         return 0;
440
441       cst = TREE_VALUE (args);
442       if (TREE_CODE (cst) != INTEGER_CST)
443         return 0;
444
445       if (TREE_INT_CST_HIGH (cst) != 0
446           || TREE_INT_CST_LOW (cst) < 0
447           || TREE_INT_CST_LOW (cst) > REGPARM_MAX)
448         return 0;
449
450       return 1;
451     }
452
453   return 0;
454 }
455
456 /* Return 0 if the attributes for two types are incompatible, 1 if they
457    are compatible, and 2 if they are nearly compatible (which causes a
458    warning to be generated).  */
459
460 int
461 i386_comp_type_attributes (type1, type2)
462      tree type1;
463      tree type2;
464 {
465   return 1;
466 }
467
468 \f
469 /* Value is the number of bytes of arguments automatically
470    popped when returning from a subroutine call.
471    FUNDECL is the declaration node of the function (as a tree),
472    FUNTYPE is the data type of the function (as a tree),
473    or for a library call it is an identifier node for the subroutine name.
474    SIZE is the number of bytes of arguments passed on the stack.
475
476    On the 80386, the RTD insn may be used to pop them if the number
477      of args is fixed, but if the number is variable then the caller
478      must pop them all.  RTD can't be used for library calls now
479      because the library is compiled with the Unix compiler.
480    Use of RTD is a selectable option, since it is incompatible with
481    standard Unix calling sequences.  If the option is not selected,
482    the caller must always pop the args.
483
484    The attribute stdcall is equivalent to RTD on a per module basis.  */
485
486 int
487 i386_return_pops_args (fundecl, funtype, size)
488      tree fundecl;
489      tree funtype;
490      int size;
491
492   int rtd = TARGET_RTD && TREE_CODE (fundecl) != IDENTIFIER_NODE;
493
494     /* Cdecl functions override -mrtd, and never pop the stack */
495   if (!lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
496   
497     /* Stdcall functions will pop the stack if not variable args */
498     if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
499       rtd = 1;
500   
501     if (rtd
502         && (TYPE_ARG_TYPES (funtype) == NULL_TREE
503             || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)))
504       return size;
505   }
506   
507   /* Lose any fake structure return argument */
508   if (aggregate_value_p (TREE_TYPE (funtype)))
509     return GET_MODE_SIZE (Pmode);
510   
511     return 0;
512 }
513
514 \f
515 /* Argument support functions.  */
516
517 /* Initialize a variable CUM of type CUMULATIVE_ARGS
518    for a call to a function whose data type is FNTYPE.
519    For a library call, FNTYPE is 0.  */
520
521 void
522 init_cumulative_args (cum, fntype, libname)
523      CUMULATIVE_ARGS *cum;      /* argument info to initialize */
524      tree fntype;               /* tree ptr for function decl */
525      rtx libname;               /* SYMBOL_REF of library name or 0 */
526 {
527   static CUMULATIVE_ARGS zero_cum;
528   tree param, next_param;
529
530   if (TARGET_DEBUG_ARG)
531     {
532       fprintf (stderr, "\ninit_cumulative_args (");
533       if (fntype)
534         {
535           tree ret_type = TREE_TYPE (fntype);
536           fprintf (stderr, "fntype code = %s, ret code = %s",
537                    tree_code_name[ (int)TREE_CODE (fntype) ],
538                    tree_code_name[ (int)TREE_CODE (ret_type) ]);
539         }
540       else
541         fprintf (stderr, "no fntype");
542
543       if (libname)
544         fprintf (stderr, ", libname = %s", XSTR (libname, 0));
545     }
546
547   *cum = zero_cum;
548
549   /* Set up the number of registers to use for passing arguments.  */
550   cum->nregs = i386_regparm;
551   if (fntype)
552     {
553       tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
554       if (attr)
555         cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
556     }
557
558   /* Determine if this function has variable arguments.  This is
559      indicated by the last argument being 'void_type_mode' if there
560      are no variable arguments.  If there are variable arguments, then
561      we won't pass anything in registers */
562
563   if (cum->nregs)
564     {
565       for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
566            param != (tree)0;
567            param = next_param)
568         {
569           next_param = TREE_CHAIN (param);
570           if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
571             cum->nregs = 0;
572         }
573     }
574
575   if (TARGET_DEBUG_ARG)
576     fprintf (stderr, ", nregs=%d )\n", cum->nregs);
577
578   return;
579 }
580
581 /* Update the data in CUM to advance over an argument
582    of mode MODE and data type TYPE.
583    (TYPE is null for libcalls where that information may not be available.)  */
584
585 void
586 function_arg_advance (cum, mode, type, named)
587      CUMULATIVE_ARGS *cum;      /* current arg information */
588      enum machine_mode mode;    /* current arg mode */
589      tree type;                 /* type of the argument or 0 if lib support */
590      int named;                 /* whether or not the argument was named */
591 {
592   int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
593   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
594
595   if (TARGET_DEBUG_ARG)
596     fprintf (stderr,
597              "function_adv( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d )\n\n",
598              words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
599
600   cum->words += words;
601   cum->nregs -= words;
602   cum->regno += words;
603
604   if (cum->nregs <= 0)
605     {
606       cum->nregs = 0;
607       cum->regno = 0;
608     }
609
610   return;
611 }
612
613 /* Define where to put the arguments to a function.
614    Value is zero to push the argument on the stack,
615    or a hard register in which to store the argument.
616
617    MODE is the argument's machine mode.
618    TYPE is the data type of the argument (as a tree).
619     This is null for libcalls where that information may
620     not be available.
621    CUM is a variable of type CUMULATIVE_ARGS which gives info about
622     the preceding args and about the function being called.
623    NAMED is nonzero if this argument is a named parameter
624     (otherwise it is an extra parameter matching an ellipsis).  */
625
626 struct rtx_def *
627 function_arg (cum, mode, type, named)
628      CUMULATIVE_ARGS *cum;      /* current arg information */
629      enum machine_mode mode;    /* current arg mode */
630      tree type;                 /* type of the argument or 0 if lib support */
631      int named;                 /* != 0 for normal args, == 0 for ... args */
632 {
633   rtx ret   = NULL_RTX;
634   int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
635   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
636
637   switch (mode)
638     {
639     default:                    /* for now, pass fp/complex values on the stack */
640       break;
641
642     case BLKmode:
643     case DImode:
644     case SImode:
645     case HImode:
646     case QImode:
647       if (words <= cum->nregs)
648         ret = gen_rtx (REG, mode, cum->regno);
649       break;
650     }
651
652   if (TARGET_DEBUG_ARG)
653     {
654       fprintf (stderr,
655                "function_arg( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d",
656                words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
657
658       if (ret)
659         fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
660       else
661         fprintf (stderr, ", stack");
662
663       fprintf (stderr, " )\n");
664     }
665
666   return ret;
667 }
668
669 /* For an arg passed partly in registers and partly in memory,
670    this is the number of registers used.
671    For args passed entirely in registers or entirely in memory, zero.  */
672
673 int
674 function_arg_partial_nregs (cum, mode, type, named)
675      CUMULATIVE_ARGS *cum;      /* current arg information */
676      enum machine_mode mode;    /* current arg mode */
677      tree type;                 /* type of the argument or 0 if lib support */
678      int named;                 /* != 0 for normal args, == 0 for ... args */
679 {
680   return 0;
681 }
682
683 \f
684 /* Output an insn whose source is a 386 integer register.  SRC is the
685    rtx for the register, and TEMPLATE is the op-code template.  SRC may
686    be either SImode or DImode.
687
688    The template will be output with operands[0] as SRC, and operands[1]
689    as a pointer to the top of the 386 stack.  So a call from floatsidf2
690    would look like this:
691
692       output_op_from_reg (operands[1], AS1 (fild%z0,%1));
693
694    where %z0 corresponds to the caller's operands[1], and is used to
695    emit the proper size suffix.
696
697    ??? Extend this to handle HImode - a 387 can load and store HImode
698    values directly. */
699
700 void
701 output_op_from_reg (src, template)
702      rtx src;
703      char *template;
704 {
705   rtx xops[4];
706   int size = GET_MODE_SIZE (GET_MODE (src));
707
708   xops[0] = src;
709   xops[1] = AT_SP (Pmode);
710   xops[2] = GEN_INT (size);
711   xops[3] = stack_pointer_rtx;
712
713   if (size > UNITS_PER_WORD)
714     {
715       rtx high;
716       if (size > 2 * UNITS_PER_WORD)
717         {
718           high = gen_rtx (REG, SImode, REGNO (src) + 2);
719           output_asm_insn (AS1 (push%L0,%0), &high);
720         }
721       high = gen_rtx (REG, SImode, REGNO (src) + 1);
722       output_asm_insn (AS1 (push%L0,%0), &high);
723     }
724   output_asm_insn (AS1 (push%L0,%0), &src);
725
726   output_asm_insn (template, xops);
727
728   output_asm_insn (AS2 (add%L3,%2,%3), xops);
729 }
730 \f
731 /* Output an insn to pop an value from the 387 top-of-stack to 386
732    register DEST. The 387 register stack is popped if DIES is true.  If
733    the mode of DEST is an integer mode, a `fist' integer store is done,
734    otherwise a `fst' float store is done. */
735
736 void
737 output_to_reg (dest, dies)
738      rtx dest;
739      int dies;
740 {
741   rtx xops[4];
742   int size = GET_MODE_SIZE (GET_MODE (dest));
743
744   xops[0] = AT_SP (Pmode);
745   xops[1] = stack_pointer_rtx;
746   xops[2] = GEN_INT (size);
747   xops[3] = dest;
748
749   output_asm_insn (AS2 (sub%L1,%2,%1), xops);
750
751   if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
752     {
753       if (dies)
754         output_asm_insn (AS1 (fistp%z3,%y0), xops);
755       else
756         output_asm_insn (AS1 (fist%z3,%y0), xops);
757     }
758   else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
759     {
760       if (dies)
761         output_asm_insn (AS1 (fstp%z3,%y0), xops);
762       else
763         {
764           if (GET_MODE (dest) == XFmode)
765             {
766               output_asm_insn (AS1 (fstp%z3,%y0), xops);
767               output_asm_insn (AS1 (fld%z3,%y0), xops);
768             }
769           else
770             output_asm_insn (AS1 (fst%z3,%y0), xops);
771         }
772     }
773   else
774     abort ();
775
776   output_asm_insn (AS1 (pop%L0,%0), &dest);
777
778   if (size > UNITS_PER_WORD)
779     {
780       dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
781       output_asm_insn (AS1 (pop%L0,%0), &dest);
782       if (size > 2 * UNITS_PER_WORD)
783         {
784           dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
785           output_asm_insn (AS1 (pop%L0,%0), &dest);
786         }
787     }
788 }
789 \f
790 char *
791 singlemove_string (operands)
792      rtx *operands;
793 {
794   rtx x;
795   if (GET_CODE (operands[0]) == MEM
796       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
797     {
798       if (XEXP (x, 0) != stack_pointer_rtx)
799         abort ();
800       return "push%L1 %1";
801     }
802   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
803     {
804       return output_move_const_single (operands);
805     }
806   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
807     return AS2 (mov%L0,%1,%0);
808   else if (CONSTANT_P (operands[1]))
809     return AS2 (mov%L0,%1,%0);
810   else
811     {
812       output_asm_insn ("push%L1 %1", operands);
813       return "pop%L0 %0";
814     }
815 }
816 \f
817 /* Return a REG that occurs in ADDR with coefficient 1.
818    ADDR can be effectively incremented by incrementing REG.  */
819
820 static rtx
821 find_addr_reg (addr)
822      rtx addr;
823 {
824   while (GET_CODE (addr) == PLUS)
825     {
826       if (GET_CODE (XEXP (addr, 0)) == REG)
827         addr = XEXP (addr, 0);
828       else if (GET_CODE (XEXP (addr, 1)) == REG)
829         addr = XEXP (addr, 1);
830       else if (CONSTANT_P (XEXP (addr, 0)))
831         addr = XEXP (addr, 1);
832       else if (CONSTANT_P (XEXP (addr, 1)))
833         addr = XEXP (addr, 0);
834       else
835         abort ();
836     }
837   if (GET_CODE (addr) == REG)
838     return addr;
839   abort ();
840 }
841
842 \f
843 /* Output an insn to add the constant N to the register X.  */
844
845 static void
846 asm_add (n, x)
847      int n;
848      rtx x;
849 {
850   rtx xops[2];
851   xops[0] = x;
852
853   if (n == -1)
854     output_asm_insn (AS1 (dec%L0,%0), xops);
855   else if (n == 1)
856     output_asm_insn (AS1 (inc%L0,%0), xops);
857   else if (n < 0)
858     {
859       xops[1] = GEN_INT (-n);
860       output_asm_insn (AS2 (sub%L0,%1,%0), xops);
861     }
862   else if (n > 0)
863     {
864       xops[1] = GEN_INT (n);
865       output_asm_insn (AS2 (add%L0,%1,%0), xops);
866     }
867 }
868
869 \f
870 /* Output assembler code to perform a doubleword move insn
871    with operands OPERANDS.  */
872
873 char *
874 output_move_double (operands)
875      rtx *operands;
876 {
877   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
878   rtx latehalf[2];
879   rtx middlehalf[2];
880   rtx xops[2];
881   rtx addreg0 = 0, addreg1 = 0;
882   int dest_overlapped_low = 0;
883   int size = GET_MODE_SIZE (GET_MODE (operands[0]));
884
885   middlehalf[0] = 0;
886   middlehalf[1] = 0;
887
888   /* First classify both operands.  */
889
890   if (REG_P (operands[0]))
891     optype0 = REGOP;
892   else if (offsettable_memref_p (operands[0]))
893     optype0 = OFFSOP;
894   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
895     optype0 = POPOP;
896   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
897     optype0 = PUSHOP;
898   else if (GET_CODE (operands[0]) == MEM)
899     optype0 = MEMOP;
900   else
901     optype0 = RNDOP;
902
903   if (REG_P (operands[1]))
904     optype1 = REGOP;
905   else if (CONSTANT_P (operands[1]))
906     optype1 = CNSTOP;
907   else if (offsettable_memref_p (operands[1]))
908     optype1 = OFFSOP;
909   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
910     optype1 = POPOP;
911   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
912     optype1 = PUSHOP;
913   else if (GET_CODE (operands[1]) == MEM)
914     optype1 = MEMOP;
915   else
916     optype1 = RNDOP;
917
918   /* Check for the cases that the operand constraints are not
919      supposed to allow to happen.  Abort if we get one,
920      because generating code for these cases is painful.  */
921
922   if (optype0 == RNDOP || optype1 == RNDOP)
923     abort ();
924
925   /* If one operand is decrementing and one is incrementing
926      decrement the former register explicitly
927      and change that operand into ordinary indexing.  */
928
929   if (optype0 == PUSHOP && optype1 == POPOP)
930     {
931       /* ??? Can this ever happen on i386? */
932       operands[0] = XEXP (XEXP (operands[0], 0), 0);
933       asm_add (-size, operands[0]);
934       if (GET_MODE (operands[1]) == XFmode)
935         operands[0] = gen_rtx (MEM, XFmode, operands[0]);
936       else if (GET_MODE (operands[0]) == DFmode)
937         operands[0] = gen_rtx (MEM, DFmode, operands[0]);
938       else
939         operands[0] = gen_rtx (MEM, DImode, operands[0]);
940       optype0 = OFFSOP;
941     }
942
943   if (optype0 == POPOP && optype1 == PUSHOP)
944     {
945       /* ??? Can this ever happen on i386? */
946       operands[1] = XEXP (XEXP (operands[1], 0), 0);
947       asm_add (-size, operands[1]);
948       if (GET_MODE (operands[1]) == XFmode)
949         operands[1] = gen_rtx (MEM, XFmode, operands[1]);
950       else if (GET_MODE (operands[1]) == DFmode)
951         operands[1] = gen_rtx (MEM, DFmode, operands[1]);
952       else
953         operands[1] = gen_rtx (MEM, DImode, operands[1]);
954       optype1 = OFFSOP;
955     }
956
957   /* If an operand is an unoffsettable memory ref, find a register
958      we can increment temporarily to make it refer to the second word.  */
959
960   if (optype0 == MEMOP)
961     addreg0 = find_addr_reg (XEXP (operands[0], 0));
962
963   if (optype1 == MEMOP)
964     addreg1 = find_addr_reg (XEXP (operands[1], 0));
965
966   /* Ok, we can do one word at a time.
967      Normally we do the low-numbered word first,
968      but if either operand is autodecrementing then we
969      do the high-numbered word first.
970
971      In either case, set up in LATEHALF the operands to use
972      for the high-numbered word and in some cases alter the
973      operands in OPERANDS to be suitable for the low-numbered word.  */
974
975   if (size == 12)
976     {
977       if (optype0 == REGOP)
978         {
979           middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
980           latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
981         }
982       else if (optype0 == OFFSOP)
983         {
984           middlehalf[0] = adj_offsettable_operand (operands[0], 4);
985           latehalf[0] = adj_offsettable_operand (operands[0], 8);
986         }
987       else
988         {
989          middlehalf[0] = operands[0];
990          latehalf[0] = operands[0];
991         }
992     
993       if (optype1 == REGOP)
994         {
995           middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
996           latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
997         }
998       else if (optype1 == OFFSOP)
999         {
1000           middlehalf[1] = adj_offsettable_operand (operands[1], 4);
1001           latehalf[1] = adj_offsettable_operand (operands[1], 8);
1002         }
1003       else if (optype1 == CNSTOP)
1004         {
1005           if (GET_CODE (operands[1]) == CONST_DOUBLE)
1006             {
1007               REAL_VALUE_TYPE r; long l[3];
1008
1009               REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
1010               REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
1011               operands[1] = GEN_INT (l[0]);
1012               middlehalf[1] = GEN_INT (l[1]);
1013               latehalf[1] = GEN_INT (l[2]);
1014             }
1015           else if (CONSTANT_P (operands[1]))
1016             /* No non-CONST_DOUBLE constant should ever appear here.  */
1017             abort ();
1018         }
1019       else
1020         {
1021           middlehalf[1] = operands[1];
1022           latehalf[1] = operands[1];
1023         }
1024     }
1025   else /* size is not 12: */
1026     {
1027       if (optype0 == REGOP)
1028         latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1029       else if (optype0 == OFFSOP)
1030         latehalf[0] = adj_offsettable_operand (operands[0], 4);
1031       else
1032         latehalf[0] = operands[0];
1033
1034       if (optype1 == REGOP)
1035         latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
1036       else if (optype1 == OFFSOP)
1037         latehalf[1] = adj_offsettable_operand (operands[1], 4);
1038       else if (optype1 == CNSTOP)
1039         split_double (operands[1], &operands[1], &latehalf[1]);
1040       else
1041         latehalf[1] = operands[1];
1042     }
1043
1044   /* If insn is effectively movd N (sp),-(sp) then we will do the
1045      high word first.  We should use the adjusted operand 1
1046      (which is N+4 (sp) or N+8 (sp))
1047      for the low word and middle word as well,
1048      to compensate for the first decrement of sp.  */
1049   if (optype0 == PUSHOP
1050       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
1051       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
1052     middlehalf[1] = operands[1] = latehalf[1];
1053
1054   /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),
1055      if the upper part of reg N does not appear in the MEM, arrange to
1056      emit the move late-half first.  Otherwise, compute the MEM address
1057      into the upper part of N and use that as a pointer to the memory
1058      operand.  */
1059   if (optype0 == REGOP
1060       && (optype1 == OFFSOP || optype1 == MEMOP))
1061     {
1062       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
1063           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
1064         {
1065           /* If both halves of dest are used in the src memory address,
1066              compute the address into latehalf of dest.  */
1067 compadr:
1068           xops[0] = latehalf[0];
1069           xops[1] = XEXP (operands[1], 0);
1070           output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
1071           if( GET_MODE (operands[1]) == XFmode )
1072             {
1073 /*          abort (); */
1074               operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
1075               middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
1076               latehalf[1] = adj_offsettable_operand (operands[1], size-4);
1077             }
1078           else
1079             {
1080               operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
1081               latehalf[1] = adj_offsettable_operand (operands[1], size-4);
1082             }
1083         }
1084       else if (size == 12
1085                  && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
1086         {
1087           /* Check for two regs used by both source and dest. */
1088           if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
1089                 || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
1090                 goto compadr;
1091
1092           /* JRV says this can't happen: */
1093           if (addreg0 || addreg1)
1094               abort();
1095
1096           /* Only the middle reg conflicts; simply put it last. */
1097           output_asm_insn (singlemove_string (operands), operands);
1098           output_asm_insn (singlemove_string (latehalf), latehalf);
1099           output_asm_insn (singlemove_string (middlehalf), middlehalf);
1100           return "";
1101         }
1102       else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
1103         /* If the low half of dest is mentioned in the source memory
1104            address, the arrange to emit the move late half first.  */
1105         dest_overlapped_low = 1;
1106     }
1107
1108   /* If one or both operands autodecrementing,
1109      do the two words, high-numbered first.  */
1110
1111   /* Likewise,  the first move would clobber the source of the second one,
1112      do them in the other order.  This happens only for registers;
1113      such overlap can't happen in memory unless the user explicitly
1114      sets it up, and that is an undefined circumstance.  */
1115
1116 /*
1117   if (optype0 == PUSHOP || optype1 == PUSHOP
1118       || (optype0 == REGOP && optype1 == REGOP
1119           && REGNO (operands[0]) == REGNO (latehalf[1]))
1120       || dest_overlapped_low)
1121 */
1122   if (optype0 == PUSHOP || optype1 == PUSHOP
1123       || (optype0 == REGOP && optype1 == REGOP
1124           && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
1125               || REGNO (operands[0]) == REGNO (latehalf[1])))
1126       || dest_overlapped_low)
1127     {
1128       /* Make any unoffsettable addresses point at high-numbered word.  */
1129       if (addreg0)
1130         asm_add (size-4, addreg0);
1131       if (addreg1)
1132         asm_add (size-4, addreg1);
1133
1134       /* Do that word.  */
1135       output_asm_insn (singlemove_string (latehalf), latehalf);
1136
1137       /* Undo the adds we just did.  */
1138       if (addreg0)
1139          asm_add (-4, addreg0);
1140       if (addreg1)
1141         asm_add (-4, addreg1);
1142
1143       if (size == 12)
1144         {
1145         output_asm_insn (singlemove_string (middlehalf), middlehalf);
1146         if (addreg0)
1147            asm_add (-4, addreg0);
1148         if (addreg1)
1149            asm_add (-4, addreg1);
1150         }
1151
1152       /* Do low-numbered word.  */
1153       return singlemove_string (operands);
1154     }
1155
1156   /* Normal case: do the two words, low-numbered first.  */
1157
1158   output_asm_insn (singlemove_string (operands), operands);
1159
1160   /* Do the middle one of the three words for long double */
1161   if (size == 12)
1162     {
1163       if (addreg0)
1164         asm_add (4, addreg0);
1165       if (addreg1)
1166         asm_add (4, addreg1);
1167
1168       output_asm_insn (singlemove_string (middlehalf), middlehalf);
1169     }
1170
1171   /* Make any unoffsettable addresses point at high-numbered word.  */
1172   if (addreg0)
1173     asm_add (4, addreg0);
1174   if (addreg1)
1175     asm_add (4, addreg1);
1176
1177   /* Do that word.  */
1178   output_asm_insn (singlemove_string (latehalf), latehalf);
1179
1180   /* Undo the adds we just did.  */
1181   if (addreg0)
1182     asm_add (4-size, addreg0);
1183   if (addreg1)
1184     asm_add (4-size, addreg1);
1185
1186   return "";
1187 }
1188
1189 \f
1190 #define MAX_TMPS 2              /* max temporary registers used */
1191
1192 /* Output the appropriate code to move push memory on the stack */
1193
1194 char *
1195 output_move_pushmem (operands, insn, length, tmp_start, n_operands)
1196      rtx operands[];
1197      rtx insn;
1198      int length;
1199      int tmp_start;
1200      int n_operands;
1201 {
1202
1203   struct {
1204     char *load;
1205     char *push;
1206     rtx   xops[2];
1207   } tmp_info[MAX_TMPS];
1208
1209   rtx src = operands[1];
1210   int max_tmps = 0;
1211   int offset = 0;
1212   int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
1213   int stack_offset = 0;
1214   int i, num_tmps;
1215   rtx xops[1];
1216
1217   if (!offsettable_memref_p (src))
1218     fatal_insn ("Source is not offsettable", insn);
1219
1220   if ((length & 3) != 0)
1221     fatal_insn ("Pushing non-word aligned size", insn);
1222
1223   /* Figure out which temporary registers we have available */
1224   for (i = tmp_start; i < n_operands; i++)
1225     {
1226       if (GET_CODE (operands[i]) == REG)
1227         {
1228           if (reg_overlap_mentioned_p (operands[i], src))
1229             continue;
1230
1231           tmp_info[ max_tmps++ ].xops[1] = operands[i];
1232           if (max_tmps == MAX_TMPS)
1233             break;
1234         }
1235     }
1236
1237   if (max_tmps == 0)
1238     for (offset = length - 4; offset >= 0; offset -= 4)
1239       {
1240         xops[0] = adj_offsettable_operand (src, offset + stack_offset);
1241         output_asm_insn (AS1(push%L0,%0), xops);
1242         if (stack_p)
1243           stack_offset += 4;
1244       }
1245
1246   else
1247     for (offset = length - 4; offset >= 0; )
1248       {
1249         for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
1250           {
1251             tmp_info[num_tmps].load    = AS2(mov%L0,%0,%1);
1252             tmp_info[num_tmps].push    = AS1(push%L0,%1);
1253             tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
1254             offset -= 4;
1255           }
1256
1257         for (i = 0; i < num_tmps; i++)
1258           output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
1259
1260         for (i = 0; i < num_tmps; i++)
1261           output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
1262
1263         if (stack_p)
1264           stack_offset += 4*num_tmps;
1265       }
1266
1267   return "";
1268 }
1269
1270 \f
1271
1272 /* Output the appropriate code to move data between two memory locations */
1273
1274 char *
1275 output_move_memory (operands, insn, length, tmp_start, n_operands)
1276      rtx operands[];
1277      rtx insn;
1278      int length;
1279      int tmp_start;
1280      int n_operands;
1281 {
1282   struct {
1283     char *load;
1284     char *store;
1285     rtx   xops[3];
1286   } tmp_info[MAX_TMPS];
1287
1288   rtx dest = operands[0];
1289   rtx src  = operands[1];
1290   rtx qi_tmp = NULL_RTX;
1291   int max_tmps = 0;
1292   int offset = 0;
1293   int i, num_tmps;
1294   rtx xops[3];
1295
1296   if (GET_CODE (dest) == MEM
1297       && GET_CODE (XEXP (dest, 0)) == PRE_INC
1298       && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
1299     return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
1300
1301   if (!offsettable_memref_p (src))
1302     fatal_insn ("Source is not offsettable", insn);
1303
1304   if (!offsettable_memref_p (dest))
1305     fatal_insn ("Destination is not offsettable", insn);
1306
1307   /* Figure out which temporary registers we have available */
1308   for (i = tmp_start; i < n_operands; i++)
1309     {
1310       if (GET_CODE (operands[i]) == REG)
1311         {
1312           if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
1313             qi_tmp = operands[i];
1314
1315           if (reg_overlap_mentioned_p (operands[i], dest))
1316             fatal_insn ("Temporary register overlaps the destination", insn);
1317
1318           if (reg_overlap_mentioned_p (operands[i], src))
1319             fatal_insn ("Temporary register overlaps the source", insn);
1320
1321           tmp_info[ max_tmps++ ].xops[2] = operands[i];
1322           if (max_tmps == MAX_TMPS)
1323             break;
1324         }
1325     }
1326
1327   if (max_tmps == 0)
1328     fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
1329
1330   if ((length & 1) != 0)
1331     {
1332       if (!qi_tmp)
1333         fatal_insn ("No byte register found when moving odd # of bytes.", insn);
1334     }
1335
1336   while (length > 1)
1337     {
1338       for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
1339         {
1340           if (length >= 4)
1341             {
1342               tmp_info[num_tmps].load    = AS2(mov%L0,%1,%2);
1343               tmp_info[num_tmps].store   = AS2(mov%L0,%2,%0);
1344               tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
1345               tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
1346               offset += 4;
1347               length -= 4;
1348             }
1349           else if (length >= 2)
1350             {
1351               tmp_info[num_tmps].load    = AS2(mov%W0,%1,%2);
1352               tmp_info[num_tmps].store   = AS2(mov%W0,%2,%0);
1353               tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
1354               tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
1355               offset += 2;
1356               length -= 2;
1357             }
1358           else
1359             break;
1360         }
1361
1362       for (i = 0; i < num_tmps; i++)
1363         output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
1364
1365       for (i = 0; i < num_tmps; i++)
1366         output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
1367     }
1368
1369   if (length == 1)
1370     {
1371       xops[0] = adj_offsettable_operand (dest, offset);
1372       xops[1] = adj_offsettable_operand (src, offset);
1373       xops[2] = qi_tmp;
1374       output_asm_insn (AS2(mov%B0,%1,%2), xops);
1375       output_asm_insn (AS2(mov%B0,%2,%0), xops);
1376     }
1377
1378   return "";
1379 }
1380
1381 \f
1382 int
1383 standard_80387_constant_p (x)
1384      rtx x;
1385 {
1386 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
1387   REAL_VALUE_TYPE d;
1388   jmp_buf handler;
1389   int is0, is1;
1390
1391   if (setjmp (handler))
1392     return 0;
1393
1394   set_float_handler (handler);
1395   REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1396   is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
1397   is1 = REAL_VALUES_EQUAL (d, dconst1);
1398   set_float_handler (NULL_PTR);
1399
1400   if (is0)
1401     return 1;
1402
1403   if (is1)
1404     return 2;
1405
1406   /* Note that on the 80387, other constants, such as pi,
1407      are much slower to load as standard constants
1408      than to load from doubles in memory!  */
1409 #endif
1410
1411   return 0;
1412 }
1413
1414 char *
1415 output_move_const_single (operands)
1416      rtx *operands;
1417 {
1418   if (FP_REG_P (operands[0]))
1419     {
1420       int conval = standard_80387_constant_p (operands[1]);
1421
1422       if (conval == 1)
1423         return "fldz";
1424
1425       if (conval == 2)
1426         return "fld1";
1427     }
1428   if (GET_CODE (operands[1]) == CONST_DOUBLE)
1429     {
1430       REAL_VALUE_TYPE r; long l;
1431
1432       if (GET_MODE (operands[1]) == XFmode)
1433         abort ();
1434
1435       REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
1436       REAL_VALUE_TO_TARGET_SINGLE (r, l);
1437       operands[1] = GEN_INT (l);
1438     }
1439   return singlemove_string (operands);
1440 }
1441 \f
1442 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1443    reference and a constant.  */
1444
1445 int
1446 symbolic_operand (op, mode)
1447      register rtx op;
1448      enum machine_mode mode;
1449 {
1450   switch (GET_CODE (op))
1451     {
1452     case SYMBOL_REF:
1453     case LABEL_REF:
1454       return 1;
1455     case CONST:
1456       op = XEXP (op, 0);
1457       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1458                || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1459               && GET_CODE (XEXP (op, 1)) == CONST_INT);
1460     default:
1461       return 0;
1462     }
1463 }
1464
1465 /* Test for a valid operand for a call instruction.
1466    Don't allow the arg pointer register or virtual regs
1467    since they may change into reg + const, which the patterns
1468    can't handle yet.  */
1469
1470 int
1471 call_insn_operand (op, mode)
1472      rtx op;
1473      enum machine_mode mode;
1474 {
1475   if (GET_CODE (op) == MEM
1476       && ((CONSTANT_ADDRESS_P (XEXP (op, 0))
1477            /* This makes a difference for PIC.  */
1478            && general_operand (XEXP (op, 0), Pmode))
1479           || (GET_CODE (XEXP (op, 0)) == REG
1480               && XEXP (op, 0) != arg_pointer_rtx
1481               && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
1482                    && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
1483     return 1;
1484   return 0;
1485 }
1486
1487 /* Like call_insn_operand but allow (mem (symbol_ref ...))
1488    even if pic.  */
1489
1490 int
1491 expander_call_insn_operand (op, mode)
1492      rtx op;
1493      enum machine_mode mode;
1494 {
1495   if (GET_CODE (op) == MEM
1496       && (CONSTANT_ADDRESS_P (XEXP (op, 0))
1497           || (GET_CODE (XEXP (op, 0)) == REG
1498               && XEXP (op, 0) != arg_pointer_rtx
1499               && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
1500                    && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
1501     return 1;
1502   return 0;
1503 }
1504
1505 /* Return 1 if OP is a comparison operator that can use the condition code
1506    generated by an arithmetic operation. */
1507
1508 int
1509 arithmetic_comparison_operator (op, mode)
1510      register rtx op;
1511      enum machine_mode mode;
1512 {
1513   enum rtx_code code;
1514
1515   if (mode != VOIDmode && mode != GET_MODE (op))
1516     return 0;
1517   code = GET_CODE (op);
1518   if (GET_RTX_CLASS (code) != '<')
1519     return 0;
1520
1521   return (code != GT && code != LE);
1522 }
1523 \f
1524 /* Returns 1 if OP contains a symbol reference */
1525
1526 int
1527 symbolic_reference_mentioned_p (op)
1528      rtx op;
1529 {
1530   register char *fmt;
1531   register int i;
1532
1533   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1534     return 1;
1535
1536   fmt = GET_RTX_FORMAT (GET_CODE (op));
1537   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1538     {
1539       if (fmt[i] == 'E')
1540         {
1541           register int j;
1542
1543           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1544             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1545               return 1;
1546         }
1547       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1548         return 1;
1549     }
1550
1551   return 0;
1552 }
1553 \f
1554 /* Attempt to expand a binary operator.  Make the expansion closer to the
1555    actual machine, then just general_operand, which will allow 3 separate
1556    memory references (one output, two input) in a single insn.  Return
1557    whether the insn fails, or succeeds.  */
1558
1559 int
1560 ix86_expand_binary_operator (code, mode, operands)
1561      enum rtx_code code;
1562      enum machine_mode mode;
1563      rtx operands[];
1564 {
1565   rtx insn;
1566   int i;
1567   int modified;
1568
1569   /* Recognize <var1> = <value> <op> <var1> for commutative operators */
1570   if (GET_RTX_CLASS (code) == 'c'
1571       && (rtx_equal_p (operands[0], operands[2])
1572           || immediate_operand (operands[1], mode)))
1573     {
1574       rtx temp = operands[1];
1575       operands[1] = operands[2];
1576       operands[2] = temp;
1577     }
1578
1579   /* If optimizing, copy to regs to improve CSE */
1580   if (TARGET_PSEUDO && optimize && ((reload_in_progress | reload_completed) == 0))
1581     {
1582       if (GET_CODE (operands[1]) == MEM && !rtx_equal_p (operands[0], operands[1]))
1583         operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
1584
1585       if (GET_CODE (operands[2]) == MEM)
1586         operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
1587
1588       if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
1589         {
1590           rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
1591           emit_move_insn (temp, operands[1]);
1592           operands[1] = temp;
1593           return TRUE;
1594         }         
1595     }
1596
1597   if (!ix86_binary_operator_ok (code, mode, operands))
1598     {
1599       /* If not optimizing, try to make a valid insn (optimize code previously did
1600          this above to improve chances of CSE) */
1601
1602       if ((!TARGET_PSEUDO || !optimize)
1603           && ((reload_in_progress | reload_completed) == 0)
1604           && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM))
1605         {
1606           modified = FALSE;
1607           if (GET_CODE (operands[1]) == MEM && !rtx_equal_p (operands[0], operands[1]))
1608             {
1609               operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
1610               modified = TRUE;
1611             }
1612
1613           if (GET_CODE (operands[2]) == MEM)
1614             {
1615               operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
1616               modified = TRUE;
1617             }
1618
1619           if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
1620             {
1621               rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
1622               emit_move_insn (temp, operands[1]);
1623               operands[1] = temp;
1624               return TRUE;
1625             }     
1626
1627           if (modified && !ix86_binary_operator_ok (code, mode, operands))
1628             return FALSE;
1629         }
1630       else
1631         return FALSE;
1632     }
1633
1634   return TRUE;
1635 }
1636 \f
1637 /* Return TRUE or FALSE depending on whether the binary operator meets the
1638    appropriate constraints.  */
1639
1640 int
1641 ix86_binary_operator_ok (code, mode, operands)
1642      enum rtx_code code;
1643      enum machine_mode mode;
1644      rtx operands[3];
1645 {
1646   return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
1647     && (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c');
1648 }
1649 \f
1650 /* Attempt to expand a unary operator.  Make the expansion closer to the
1651    actual machine, then just general_operand, which will allow 2 separate
1652    memory references (one output, one input) in a single insn.  Return
1653    whether the insn fails, or succeeds.  */
1654
1655 int
1656 ix86_expand_unary_operator (code, mode, operands)
1657      enum rtx_code code;
1658      enum machine_mode mode;
1659      rtx operands[];
1660 {
1661   rtx insn;
1662
1663   /* If optimizing, copy to regs to improve CSE */
1664   if (TARGET_PSEUDO
1665       && optimize
1666       && ((reload_in_progress | reload_completed) == 0)
1667       && GET_CODE (operands[1]) == MEM)
1668     {
1669       operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
1670     }
1671
1672   if (!ix86_unary_operator_ok (code, mode, operands))
1673     {
1674       if ((!TARGET_PSEUDO || !optimize)
1675           && ((reload_in_progress | reload_completed) == 0)
1676           && GET_CODE (operands[1]) == MEM)
1677         {
1678           operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
1679           if (!ix86_unary_operator_ok (code, mode, operands))
1680             return FALSE;
1681         }
1682       else
1683         return FALSE;
1684     }
1685
1686   return TRUE;
1687 }
1688 \f
1689 /* Return TRUE or FALSE depending on whether the unary operator meets the
1690    appropriate constraints.  */
1691
1692 int
1693 ix86_unary_operator_ok (code, mode, operands)
1694      enum rtx_code code;
1695      enum machine_mode mode;
1696      rtx operands[2];
1697 {
1698   return TRUE;
1699 }
1700
1701 \f
1702
1703 static rtx pic_label_rtx;
1704 static char pic_label_name [256];
1705 static int pic_label_no = 0;
1706
1707 /* This function generates code for -fpic that loads %ebx with
1708    with the return address of the caller and then returns.  */
1709 void
1710 asm_output_function_prefix (file, name)
1711     FILE * file;
1712     char * name;
1713 {
1714   rtx xops[2];
1715   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
1716                                   || current_function_uses_const_pool);
1717   xops[0] = pic_offset_table_rtx;
1718   xops[1] = stack_pointer_rtx;
1719
1720   /* deep branch prediction favors having a return for every call */
1721   if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
1722     {
1723       tree prologue_node;
1724
1725       if (pic_label_rtx == 0)
1726         {
1727           pic_label_rtx = (rtx) gen_label_rtx ();
1728           sprintf (pic_label_name, "LPR%d", pic_label_no++);
1729           LABEL_NAME (pic_label_rtx) = pic_label_name;
1730         }
1731       prologue_node = make_node (FUNCTION_DECL);
1732       DECL_RESULT (prologue_node) = 0;
1733 #ifdef ASM_DECLARE_FUNCTION_NAME
1734       ASM_DECLARE_FUNCTION_NAME (file, pic_label_name, prologue_node);
1735 #endif
1736       output_asm_insn ("movl (%1),%0", xops);
1737       output_asm_insn ("ret", xops);
1738     }
1739 }
1740
1741 /* Set up the stack and frame (if desired) for the function.  */
1742
1743 void
1744 function_prologue (file, size)
1745      FILE *file;
1746      int size;
1747 {
1748   register int regno;
1749   int limit;
1750   rtx xops[4];
1751   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
1752                                   || current_function_uses_const_pool);
1753   long tsize = get_frame_size ();
1754
1755   /* pic references don't explicitly mention pic_offset_table_rtx */
1756   if (TARGET_SCHEDULE_PROLOGUE)
1757     {
1758       pic_label_rtx = 0;
1759       return;
1760     }
1761   
1762   xops[0] = stack_pointer_rtx;
1763   xops[1] = frame_pointer_rtx;
1764   xops[2] = GEN_INT (tsize);
1765
1766   if (frame_pointer_needed)
1767     {
1768       output_asm_insn ("push%L1 %1", xops); 
1769       output_asm_insn (AS2 (mov%L0,%0,%1), xops); 
1770     }
1771
1772   if (tsize == 0)
1773     ;
1774   else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
1775     output_asm_insn (AS2 (sub%L0,%2,%0), xops);
1776   else 
1777     {
1778       xops[3] = gen_rtx (REG, SImode, 0);
1779       output_asm_insn (AS2 (mov%L0,%2,%3), xops);
1780       
1781       xops[3] = gen_rtx (SYMBOL_REF, Pmode, "_alloca");
1782       output_asm_insn (AS1 (call,%P3), xops);
1783     }
1784
1785   /* Note If use enter it is NOT reversed args.
1786      This one is not reversed from intel!!
1787      I think enter is slower.  Also sdb doesn't like it.
1788      But if you want it the code is:
1789      {
1790      xops[3] = const0_rtx;
1791      output_asm_insn ("enter %2,%3", xops);
1792      }
1793      */
1794   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
1795   for (regno = limit - 1; regno >= 0; regno--)
1796     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1797         || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1798       {
1799         xops[0] = gen_rtx (REG, SImode, regno);
1800         output_asm_insn ("push%L0 %0", xops);
1801       }
1802
1803   if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
1804     {
1805       xops[0] = pic_offset_table_rtx;
1806       xops[1] = gen_rtx (SYMBOL_REF, Pmode, LABEL_NAME (pic_label_rtx));
1807
1808       output_asm_insn (AS1 (call,%P1), xops);
1809       output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_,%0", xops);
1810       pic_label_rtx = 0;
1811     }
1812   else if (pic_reg_used)
1813     {
1814     xops[0] = pic_offset_table_rtx;
1815     xops[1] = (rtx) gen_label_rtx ();
1816  
1817       output_asm_insn (AS1 (call,%P1), xops);
1818       ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
1819       output_asm_insn (AS1 (pop%L0,%0), xops);
1820       output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
1821   } 
1822 }
1823
1824 /* This function generates the assembly code for function entry.
1825    FILE is an stdio stream to output the code to.
1826    SIZE is an int: how many units of temporary storage to allocate. */
1827
1828 void
1829 ix86_expand_prologue ()
1830 {
1831   register int regno;
1832   int limit;
1833   rtx xops[4];
1834   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
1835                                   || current_function_uses_const_pool);
1836   long tsize = get_frame_size ();
1837   rtx insn;
1838
1839   if (!TARGET_SCHEDULE_PROLOGUE)
1840     return;
1841   
1842   xops[0] = stack_pointer_rtx;
1843   xops[1] = frame_pointer_rtx;
1844   xops[2] = GEN_INT (tsize);
1845   if (frame_pointer_needed)
1846     {
1847       insn = emit_insn
1848         (gen_rtx (SET, 0,
1849                   gen_rtx (MEM, SImode,
1850                            gen_rtx (PRE_DEC, SImode, stack_pointer_rtx)),
1851                   frame_pointer_rtx));
1852       RTX_FRAME_RELATED_P (insn) = 1;
1853       insn = emit_move_insn (xops[1], xops[0]);
1854       RTX_FRAME_RELATED_P (insn) = 1;
1855     }
1856
1857   if (tsize == 0)
1858     ;
1859   else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
1860     {
1861       insn = emit_insn (gen_subsi3 (xops[0], xops[0], xops[2]));
1862       RTX_FRAME_RELATED_P (insn) = 1;
1863     }
1864   else 
1865     {
1866       xops[3] = gen_rtx (REG, SImode, 0);
1867       emit_move_insn (xops[3], xops[2]);
1868       xops[3] = gen_rtx (MEM, FUNCTION_MODE,
1869                          gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
1870       emit_call_insn (gen_rtx (CALL, VOIDmode,
1871                                xops[3], const0_rtx));
1872     }
1873
1874   /* Note If use enter it is NOT reversed args.
1875      This one is not reversed from intel!!
1876      I think enter is slower.  Also sdb doesn't like it.
1877      But if you want it the code is:
1878      {
1879      xops[3] = const0_rtx;
1880      output_asm_insn ("enter %2,%3", xops);
1881      }
1882      */
1883   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
1884   for (regno = limit - 1; regno >= 0; regno--)
1885     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1886         || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1887       {
1888         xops[0] = gen_rtx (REG, SImode, regno);
1889         insn = emit_insn
1890           (gen_rtx (SET, 0,
1891                     gen_rtx (MEM, SImode,
1892                              gen_rtx (PRE_DEC, SImode, stack_pointer_rtx)),
1893                     xops[0]));
1894         
1895         RTX_FRAME_RELATED_P (insn) = 1;
1896       }
1897
1898   if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
1899     {
1900       xops[0] = pic_offset_table_rtx;
1901       if (pic_label_rtx == 0)
1902         {
1903         pic_label_rtx = (rtx) gen_label_rtx ();
1904           sprintf (pic_label_name, "LPR%d", pic_label_no++);
1905           LABEL_NAME (pic_label_rtx) = pic_label_name;
1906         }
1907       xops[1] = gen_rtx (MEM, QImode, gen_rtx (SYMBOL_REF, Pmode, LABEL_NAME (pic_label_rtx)));
1908
1909       emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
1910       emit_insn (gen_prologue_set_got (xops[0], 
1911                  gen_rtx (SYMBOL_REF, Pmode, "$_GLOBAL_OFFSET_TABLE_"), 
1912                  gen_rtx (CONST_INT, Pmode, CODE_LABEL_NUMBER(xops[1]))));
1913     }
1914   else if (pic_reg_used)
1915     {
1916     xops[0] = pic_offset_table_rtx;
1917     xops[1] = (rtx) gen_label_rtx ();
1918  
1919       emit_insn (gen_prologue_get_pc (xops[0], gen_rtx (CONST_INT, Pmode, CODE_LABEL_NUMBER(xops[1]))));
1920       emit_insn (gen_pop (xops[0]));
1921       emit_insn (gen_prologue_set_got (xops[0], 
1922                  gen_rtx (SYMBOL_REF, Pmode, "$_GLOBAL_OFFSET_TABLE_"), 
1923                  gen_rtx (CONST_INT, Pmode, CODE_LABEL_NUMBER (xops[1]))));
1924   } 
1925 }
1926
1927 /* Restore function stack, frame, and registers. */ 
1928
1929 void
1930 function_epilogue (file, size)
1931      FILE *file;
1932      int size;
1933 {
1934 }
1935
1936 /* Return 1 if it is appropriate to emit `ret' instructions in the
1937    body of a function.  Do this only if the epilogue is simple, needing a
1938    couple of insns.  Prior to reloading, we can't tell how many registers
1939    must be saved, so return 0 then.  Return 0 if there is no frame 
1940    marker to de-allocate.
1941
1942    If NON_SAVING_SETJMP is defined and true, then it is not possible
1943    for the epilogue to be simple, so return 0.  This is a special case
1944    since NON_SAVING_SETJMP will not cause regs_ever_live to change
1945    until final, but jump_optimize may need to know sooner if a
1946    `return' is OK.  */
1947
1948 int
1949 ix86_can_use_return_insn_p ()
1950 {
1951   int regno;
1952   int nregs = 0;
1953   int reglimit = (frame_pointer_needed
1954                   ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
1955   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
1956                                   || current_function_uses_const_pool);
1957
1958 #ifdef NON_SAVING_SETJMP
1959   if (NON_SAVING_SETJMP && current_function_calls_setjmp)
1960     return 0;
1961 #endif
1962
1963   if (! reload_completed)
1964     return 0;
1965
1966   for (regno = reglimit - 1; regno >= 0; regno--)
1967     if ((regs_ever_live[regno] && ! call_used_regs[regno])
1968         || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
1969       nregs++;
1970
1971   return nregs == 0 || ! frame_pointer_needed;
1972 }
1973
1974 \f
1975 /* This function generates the assembly code for function exit.
1976    FILE is an stdio stream to output the code to.
1977    SIZE is an int: how many units of temporary storage to deallocate. */
1978
1979 void
1980 ix86_expand_epilogue ()
1981 {
1982   register int regno;
1983   register int nregs, limit;
1984   int offset;
1985   rtx xops[3];
1986   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
1987                                   || current_function_uses_const_pool);
1988   long tsize = get_frame_size ();
1989
1990   /* Compute the number of registers to pop */
1991
1992   limit = (frame_pointer_needed
1993            ? FRAME_POINTER_REGNUM
1994            : STACK_POINTER_REGNUM);
1995
1996   nregs = 0;
1997
1998   for (regno = limit - 1; regno >= 0; regno--)
1999     if ((regs_ever_live[regno] && ! call_used_regs[regno])
2000         || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
2001       nregs++;
2002
2003   /* sp is often  unreliable so we must go off the frame pointer,
2004    */
2005
2006   /* In reality, we may not care if sp is unreliable, because we can
2007      restore the register relative to the frame pointer.  In theory,
2008      since each move is the same speed as a pop, and we don't need the
2009      leal, this is faster.  For now restore multiple registers the old
2010      way. */
2011
2012   offset = -tsize - (nregs * UNITS_PER_WORD);
2013
2014   xops[2] = stack_pointer_rtx;
2015
2016   if (nregs > 1 || ! frame_pointer_needed)
2017     {
2018       if (frame_pointer_needed)
2019         {
2020           xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
2021           emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));
2022 /*        output_asm_insn (AS2 (lea%L2,%0,%2), xops);*/
2023         }
2024
2025       for (regno = 0; regno < limit; regno++)
2026         if ((regs_ever_live[regno] && ! call_used_regs[regno])
2027             || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
2028           {
2029             xops[0] = gen_rtx (REG, SImode, regno);
2030             emit_insn (gen_pop (xops[0]));
2031 /*          output_asm_insn ("pop%L0 %0", xops);*/
2032           }
2033     }
2034   else
2035     for (regno = 0; regno < limit; regno++)
2036       if ((regs_ever_live[regno] && ! call_used_regs[regno])
2037           || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
2038         {
2039           xops[0] = gen_rtx (REG, SImode, regno);
2040           xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
2041           emit_move_insn (xops[0], xops[1]);
2042 /*        output_asm_insn (AS2 (mov%L0,%1,%0), xops);*/
2043           offset += 4;
2044         }
2045
2046   if (frame_pointer_needed)
2047     {
2048       /* If not an i386, mov & pop is faster than "leave". */
2049
2050       if (TARGET_USE_LEAVE)
2051         emit_insn (gen_leave());
2052 /*      output_asm_insn ("leave", xops);*/
2053       else
2054         {
2055           xops[0] = frame_pointer_rtx;
2056           xops[1] = stack_pointer_rtx;
2057           emit_insn (gen_epilogue_set_stack_ptr());
2058 /*        output_asm_insn (AS2 (mov%L2,%0,%2), xops);*/
2059           emit_insn (gen_pop (xops[0]));
2060 /*        output_asm_insn ("pop%L0 %0", xops);*/
2061         }
2062     }
2063   else if (tsize)
2064     {
2065       /* If there is no frame pointer, we must still release the frame. */
2066
2067       xops[0] = GEN_INT (tsize);
2068       emit_insn (gen_rtx (SET, SImode,
2069                           xops[2],
2070                           gen_rtx (PLUS, SImode,
2071                                    xops[2],
2072                                    xops[0])));
2073 /*      output_asm_insn (AS2 (add%L2,%0,%2), xops);*/
2074     }
2075
2076 #ifdef FUNCTION_BLOCK_PROFILER_EXIT
2077   if (profile_block_flag == 2)
2078     {
2079       FUNCTION_BLOCK_PROFILER_EXIT(file);
2080     }
2081 #endif
2082
2083   if (current_function_pops_args && current_function_args_size)
2084     {
2085       xops[1] = GEN_INT (current_function_pops_args);
2086
2087       /* i386 can only pop 32K bytes (maybe 64K?  Is it signed?).  If
2088          asked to pop more, pop return address, do explicit add, and jump
2089          indirectly to the caller. */
2090
2091       if (current_function_pops_args >= 32768)
2092         {
2093           /* ??? Which register to use here? */
2094           xops[0] = gen_rtx (REG, SImode, 2);
2095           emit_insn (gen_pop (xops[0]));
2096 /*        output_asm_insn ("pop%L0 %0", xops);*/
2097           emit_insn (gen_rtx (SET, SImode,
2098                               xops[2],
2099                               gen_rtx (PLUS, SImode,
2100                                        xops[1],
2101                                        xops[2])));
2102 /*        output_asm_insn (AS2 (add%L2,%1,%2), xops);*/
2103           emit_jump_insn (xops[0]);
2104 /*        output_asm_insn ("jmp %*%0", xops);*/
2105         }
2106       else
2107         emit_jump_insn (gen_return_pop_internal (xops[1]));
2108 /*        output_asm_insn ("ret %1", xops);*/
2109     }
2110   else
2111 /*    output_asm_insn ("ret", xops);*/
2112  emit_jump_insn (gen_return_internal ());
2113 }
2114
2115 \f
2116 /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
2117    that is a valid memory address for an instruction.
2118    The MODE argument is the machine mode for the MEM expression
2119    that wants to use this address.
2120
2121    On x86, legitimate addresses are:
2122         base                            movl (base),reg
2123         displacement                    movl disp,reg
2124         base + displacement             movl disp(base),reg
2125         index + base                    movl (base,index),reg
2126         (index + base) + displacement   movl disp(base,index),reg
2127         index*scale                     movl (,index,scale),reg
2128         index*scale + disp              movl disp(,index,scale),reg
2129         index*scale + base              movl (base,index,scale),reg
2130         (index*scale + base) + disp     movl disp(base,index,scale),reg
2131
2132         In each case, scale can be 1, 2, 4, 8.  */
2133
2134 /* This is exactly the same as print_operand_addr, except that
2135    it recognizes addresses instead of printing them.
2136
2137    It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should
2138    convert common non-canonical forms to canonical form so that they will
2139    be recognized.  */
2140
2141 #define ADDR_INVALID(msg,insn)                                          \
2142 do {                                                                    \
2143   if (TARGET_DEBUG_ADDR)                                                \
2144     {                                                                   \
2145       fprintf (stderr, msg);                                            \
2146       debug_rtx (insn);                                                 \
2147     }                                                                   \
2148 } while (0)
2149
2150 int
2151 legitimate_address_p (mode, addr, strict)
2152      enum machine_mode mode;
2153      register rtx addr;
2154      int strict;
2155 {
2156   rtx base  = NULL_RTX;
2157   rtx indx  = NULL_RTX;
2158   rtx scale = NULL_RTX;
2159   rtx disp  = NULL_RTX;
2160
2161   if (TARGET_DEBUG_ADDR)
2162     {
2163       fprintf (stderr,
2164                "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
2165                GET_MODE_NAME (mode), strict);
2166
2167       debug_rtx (addr);
2168     }
2169
2170   if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
2171       base = addr;                              /* base reg */
2172
2173   else if (GET_CODE (addr) == PLUS)
2174     {
2175       rtx op0 = XEXP (addr, 0);
2176       rtx op1 = XEXP (addr, 1);
2177       enum rtx_code code0 = GET_CODE (op0);
2178       enum rtx_code code1 = GET_CODE (op1);
2179
2180       if (code0 == REG || code0 == SUBREG)
2181         {
2182           if (code1 == REG || code1 == SUBREG)
2183             {
2184               indx = op0;                       /* index + base */
2185               base = op1;
2186             }
2187
2188           else
2189             {
2190               base = op0;                       /* base + displacement */
2191               disp = op1;
2192             }
2193         }
2194
2195       else if (code0 == MULT)
2196         {
2197           indx  = XEXP (op0, 0);
2198           scale = XEXP (op0, 1);
2199
2200           if (code1 == REG || code1 == SUBREG)
2201             base = op1;                         /* index*scale + base */
2202
2203           else
2204             disp = op1;                         /* index*scale + disp */
2205         }
2206
2207       else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
2208         {
2209           indx  = XEXP (XEXP (op0, 0), 0);      /* index*scale + base + disp */
2210           scale = XEXP (XEXP (op0, 0), 1);
2211           base  = XEXP (op0, 1);
2212           disp  = op1;
2213         }
2214
2215       else if (code0 == PLUS)
2216         {
2217           indx = XEXP (op0, 0);                 /* index + base + disp */
2218           base = XEXP (op0, 1);
2219           disp = op1;
2220         }
2221
2222       else
2223         {
2224           ADDR_INVALID ("PLUS subcode is not valid.\n", op0);
2225           return FALSE;
2226         }
2227     }
2228
2229   else if (GET_CODE (addr) == MULT)
2230     {
2231       indx  = XEXP (addr, 0);                   /* index*scale */
2232       scale = XEXP (addr, 1);
2233     }
2234
2235   else
2236     disp = addr;                                /* displacement */
2237
2238   /* Allow arg pointer and stack pointer as index if there is not scaling */
2239   if (base && indx && !scale
2240       && (indx == arg_pointer_rtx || indx == stack_pointer_rtx))
2241     {
2242       rtx tmp = base;
2243       base = indx;
2244       indx = tmp;
2245     }
2246
2247   /* Validate base register */
2248   /* Don't allow SUBREG's here, it can lead to spill failures when the base
2249      is one word out of a two word structure, which is represented internally
2250      as a DImode int.  */
2251   if (base)
2252     {
2253       if (GET_CODE (base) != REG)
2254         {
2255           ADDR_INVALID ("Base is not a register.\n", base);
2256           return FALSE;
2257         }
2258
2259       if ((strict && !REG_OK_FOR_BASE_STRICT_P (base))
2260           || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base)))
2261         {
2262           ADDR_INVALID ("Base is not valid.\n", base);
2263           return FALSE;
2264         }
2265     }
2266
2267   /* Validate index register */
2268   /* Don't allow SUBREG's here, it can lead to spill failures when the index
2269      is one word out of a two word structure, which is represented internally
2270      as a DImode int.  */
2271   if (indx)
2272     {
2273       if (GET_CODE (indx) != REG)
2274         {
2275           ADDR_INVALID ("Index is not a register.\n", indx);
2276           return FALSE;
2277         }
2278
2279       if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx))
2280           || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
2281         {
2282           ADDR_INVALID ("Index is not valid.\n", indx);
2283           return FALSE;
2284         }
2285     }
2286   else if (scale)
2287     abort ();                                   /* scale w/o index invalid */
2288
2289   /* Validate scale factor */
2290   if (scale)
2291     {
2292       HOST_WIDE_INT value;
2293
2294       if (GET_CODE (scale) != CONST_INT)
2295         {
2296           ADDR_INVALID ("Scale is not valid.\n", scale);
2297           return FALSE;
2298         }
2299
2300       value = INTVAL (scale);
2301       if (value != 1 && value != 2 && value != 4 && value != 8)
2302         {
2303           ADDR_INVALID ("Scale is not a good multiplier.\n", scale);
2304           return FALSE;
2305         }
2306     }
2307
2308   /* Validate displacement
2309      Constant pool addresses must be handled special.  They are
2310      considered legitimate addresses, but only if not used with regs.
2311      When printed, the output routines know to print the reference with the
2312      PIC reg, even though the PIC reg doesn't appear in the RTL. */
2313   if (disp)
2314     {
2315       if (GET_CODE (disp) == SYMBOL_REF
2316           && CONSTANT_POOL_ADDRESS_P (disp)
2317           && !base
2318           && !indx)
2319         ;
2320
2321       else if (!CONSTANT_ADDRESS_P (disp))
2322         {
2323           ADDR_INVALID ("Displacement is not valid.\n", disp);
2324           return FALSE;
2325         }
2326
2327       else if (GET_CODE (disp) == CONST_DOUBLE)
2328         {
2329           ADDR_INVALID ("Displacement is a const_double.\n", disp);
2330           return FALSE;
2331         }
2332
2333       else if (flag_pic && SYMBOLIC_CONST (disp)
2334                && base != pic_offset_table_rtx
2335                && (indx != pic_offset_table_rtx || scale != NULL_RTX))
2336         {
2337           ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
2338           return FALSE;
2339         }
2340
2341       else if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
2342                && (base != NULL_RTX || indx != NULL_RTX))
2343         {
2344           ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp);
2345           return FALSE;
2346         }
2347     }
2348
2349   if (TARGET_DEBUG_ADDR)
2350     fprintf (stderr, "Address is valid.\n");
2351
2352   /* Everything looks valid, return true */
2353   return TRUE;
2354 }
2355
2356 \f
2357 /* Return a legitimate reference for ORIG (an address) using the
2358    register REG.  If REG is 0, a new pseudo is generated.
2359
2360    There are three types of references that must be handled:
2361
2362    1. Global data references must load the address from the GOT, via
2363       the PIC reg.  An insn is emitted to do this load, and the reg is
2364       returned.
2365
2366    2. Static data references must compute the address as an offset
2367       from the GOT, whose base is in the PIC reg.  An insn is emitted to
2368       compute the address into a reg, and the reg is returned.  Static
2369       data objects have SYMBOL_REF_FLAG set to differentiate them from
2370       global data objects.
2371
2372    3. Constant pool addresses must be handled special.  They are
2373       considered legitimate addresses, but only if not used with regs.
2374       When printed, the output routines know to print the reference with the
2375       PIC reg, even though the PIC reg doesn't appear in the RTL.
2376
2377    GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
2378    reg also appears in the address (except for constant pool references,
2379    noted above).
2380
2381    "switch" statements also require special handling when generating
2382    PIC code.  See comments by the `casesi' insn in i386.md for details.  */
2383
2384 rtx
2385 legitimize_pic_address (orig, reg)
2386      rtx orig;
2387      rtx reg;
2388 {
2389   rtx addr = orig;
2390   rtx new = orig;
2391
2392   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
2393     {
2394       if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
2395         reg = new = orig;
2396       else
2397         {
2398           if (reg == 0)
2399             reg = gen_reg_rtx (Pmode);
2400
2401           if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
2402               || GET_CODE (addr) == LABEL_REF)
2403             new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
2404           else
2405             new = gen_rtx (MEM, Pmode,
2406                            gen_rtx (PLUS, Pmode,
2407                                     pic_offset_table_rtx, orig));
2408
2409           emit_move_insn (reg, new);
2410         }
2411       current_function_uses_pic_offset_table = 1;
2412       return reg;
2413     }
2414   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
2415     {
2416       rtx base;
2417
2418       if (GET_CODE (addr) == CONST)
2419         {
2420           addr = XEXP (addr, 0);
2421           if (GET_CODE (addr) != PLUS)
2422             abort ();
2423         }
2424
2425       if (XEXP (addr, 0) == pic_offset_table_rtx)
2426         return orig;
2427
2428       if (reg == 0)
2429         reg = gen_reg_rtx (Pmode);
2430
2431       base = legitimize_pic_address (XEXP (addr, 0), reg);
2432       addr = legitimize_pic_address (XEXP (addr, 1),
2433                                      base == reg ? NULL_RTX : reg);
2434
2435       if (GET_CODE (addr) == CONST_INT)
2436         return plus_constant (base, INTVAL (addr));
2437
2438       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
2439         {
2440           base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
2441           addr = XEXP (addr, 1);
2442         }
2443         return gen_rtx (PLUS, Pmode, base, addr);
2444     }
2445   return new;
2446 }
2447 \f
2448
2449 /* Emit insns to move operands[1] into operands[0].  */
2450
2451 void
2452 emit_pic_move (operands, mode)
2453      rtx *operands;
2454      enum machine_mode mode;
2455 {
2456   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2457
2458   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2459     operands[1] = (rtx) force_reg (SImode, operands[1]);
2460   else
2461     operands[1] = legitimize_pic_address (operands[1], temp);
2462 }
2463
2464 \f
2465 /* Try machine-dependent ways of modifying an illegitimate address
2466    to be legitimate.  If we find one, return the new, valid address.
2467    This macro is used in only one place: `memory_address' in explow.c.
2468
2469    OLDX is the address as it was before break_out_memory_refs was called.
2470    In some cases it is useful to look at this to decide what needs to be done.
2471
2472    MODE and WIN are passed so that this macro can use
2473    GO_IF_LEGITIMATE_ADDRESS.
2474
2475    It is always safe for this macro to do nothing.  It exists to recognize
2476    opportunities to optimize the output.
2477
2478    For the 80386, we handle X+REG by loading X into a register R and
2479    using R+REG.  R will go in a general reg and indexing will be used.
2480    However, if REG is a broken-out memory address or multiplication,
2481    nothing needs to be done because REG can certainly go in a general reg.
2482
2483    When -fpic is used, special handling is needed for symbolic references.
2484    See comments by legitimize_pic_address in i386.c for details.  */
2485
2486 rtx
2487 legitimize_address (x, oldx, mode)
2488      register rtx x;
2489      register rtx oldx;
2490      enum machine_mode mode;
2491 {
2492   int changed = 0;
2493   unsigned log;
2494
2495   if (TARGET_DEBUG_ADDR)
2496     {
2497       fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode));
2498       debug_rtx (x);
2499     }
2500
2501   if (flag_pic && SYMBOLIC_CONST (x))
2502     return legitimize_pic_address (x, 0);
2503
2504   /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
2505   if (GET_CODE (x) == ASHIFT
2506       && GET_CODE (XEXP (x, 1)) == CONST_INT
2507       && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
2508     {
2509       changed = 1;
2510       x = gen_rtx (MULT, Pmode,
2511                    force_reg (Pmode, XEXP (x, 0)),
2512                    GEN_INT (1 << log));
2513     }
2514
2515   if (GET_CODE (x) == PLUS)
2516     {
2517       /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
2518       if (GET_CODE (XEXP (x, 0)) == ASHIFT
2519           && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
2520           && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
2521         {
2522           changed = 1;
2523           XEXP (x, 0) = gen_rtx (MULT, Pmode,
2524                                  force_reg (Pmode, XEXP (XEXP (x, 0), 0)),
2525                                  GEN_INT (1 << log));
2526         }
2527
2528       if (GET_CODE (XEXP (x, 1)) == ASHIFT
2529           && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
2530           && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4)
2531         {
2532           changed = 1;
2533           XEXP (x, 1) = gen_rtx (MULT, Pmode,
2534                                  force_reg (Pmode, XEXP (XEXP (x, 1), 0)),
2535                                  GEN_INT (1 << log));
2536         }
2537
2538       /* Put multiply first if it isn't already */
2539       if (GET_CODE (XEXP (x, 1)) == MULT)
2540         {
2541           rtx tmp = XEXP (x, 0);
2542           XEXP (x, 0) = XEXP (x, 1);
2543           XEXP (x, 1) = tmp;
2544           changed = 1;
2545         }
2546
2547       /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const)))
2548          into (plus (plus (mult (reg) (const)) (reg)) (const)).  This can be
2549          created by virtual register instantiation, register elimination, and
2550          similar optimizations.  */
2551       if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS)
2552         {
2553           changed = 1;
2554           x = gen_rtx (PLUS, Pmode,
2555                        gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)),
2556                        XEXP (XEXP (x, 1), 1));
2557         }
2558
2559       /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
2560          into (plus (plus (mult (reg) (const)) (reg)) (const)).  */
2561       else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
2562                && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
2563                && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
2564                && CONSTANT_P (XEXP (x, 1)))
2565         {
2566           rtx constant, other;
2567
2568           if (GET_CODE (XEXP (x, 1)) == CONST_INT)
2569             {
2570               constant = XEXP (x, 1);
2571               other = XEXP (XEXP (XEXP (x, 0), 1), 1);
2572             }
2573           else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT)
2574             {
2575               constant = XEXP (XEXP (XEXP (x, 0), 1), 1);
2576               other = XEXP (x, 1);
2577             }
2578           else
2579             constant = 0;
2580
2581           if (constant)
2582             {
2583               changed = 1;
2584               x = gen_rtx (PLUS, Pmode,
2585                            gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0),
2586                                     XEXP (XEXP (XEXP (x, 0), 1), 0)),
2587                            plus_constant (other, INTVAL (constant)));
2588             }
2589         }
2590
2591       if (changed && legitimate_address_p (mode, x, FALSE))
2592         return x;
2593
2594       if (GET_CODE (XEXP (x, 0)) == MULT)
2595         {
2596           changed = 1;
2597           XEXP (x, 0) = force_operand (XEXP (x, 0), 0);
2598         }
2599
2600       if (GET_CODE (XEXP (x, 1)) == MULT)
2601         {
2602           changed = 1;
2603           XEXP (x, 1) = force_operand (XEXP (x, 1), 0);
2604         }
2605
2606       if (changed
2607           && GET_CODE (XEXP (x, 1)) == REG
2608           && GET_CODE (XEXP (x, 0)) == REG)
2609         return x;
2610
2611       if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
2612         {
2613           changed = 1;
2614           x = legitimize_pic_address (x, 0);
2615         }
2616
2617       if (changed && legitimate_address_p (mode, x, FALSE))
2618         return x;
2619
2620       if (GET_CODE (XEXP (x, 0)) == REG)
2621         {
2622           register rtx temp = gen_reg_rtx (Pmode);
2623           register rtx val  = force_operand (XEXP (x, 1), temp);
2624           if (val != temp)
2625             emit_move_insn (temp, val);
2626
2627           XEXP (x, 1) = temp;
2628           return x;
2629         }
2630
2631       else if (GET_CODE (XEXP (x, 1)) == REG)
2632         {
2633           register rtx temp = gen_reg_rtx (Pmode);
2634           register rtx val  = force_operand (XEXP (x, 0), temp);
2635           if (val != temp)
2636             emit_move_insn (temp, val);
2637
2638           XEXP (x, 0) = temp;
2639           return x;
2640         }
2641     }
2642
2643   return x;
2644 }
2645
2646 \f
2647 /* Print an integer constant expression in assembler syntax.  Addition
2648    and subtraction are the only arithmetic that may appear in these
2649    expressions.  FILE is the stdio stream to write to, X is the rtx, and
2650    CODE is the operand print code from the output string.  */
2651
2652 static void
2653 output_pic_addr_const (file, x, code)
2654      FILE *file;
2655      rtx x;
2656      int code;
2657 {
2658   char buf[256];
2659
2660   switch (GET_CODE (x))
2661     {
2662     case PC:
2663       if (flag_pic)
2664         putc ('.', file);
2665       else
2666         abort ();
2667       break;
2668
2669     case SYMBOL_REF:
2670     case LABEL_REF:
2671       if (GET_CODE (x) == SYMBOL_REF)
2672         assemble_name (file, XSTR (x, 0));
2673       else
2674         {
2675           ASM_GENERATE_INTERNAL_LABEL (buf, "L",
2676                                        CODE_LABEL_NUMBER (XEXP (x, 0)));
2677           assemble_name (asm_out_file, buf);
2678         }
2679
2680       if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
2681         fprintf (file, "@GOTOFF(%%ebx)");
2682       else if (code == 'P')
2683         fprintf (file, "@PLT");
2684       else if (GET_CODE (x) == LABEL_REF)
2685         fprintf (file, "@GOTOFF");
2686       else if (! SYMBOL_REF_FLAG (x))
2687         fprintf (file, "@GOT");
2688       else
2689         fprintf (file, "@GOTOFF");
2690
2691       break;
2692
2693     case CODE_LABEL:
2694       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
2695       assemble_name (asm_out_file, buf);
2696       break;
2697
2698     case CONST_INT:
2699       fprintf (file, "%d", INTVAL (x));
2700       break;
2701
2702     case CONST:
2703       /* This used to output parentheses around the expression,
2704          but that does not work on the 386 (either ATT or BSD assembler).  */
2705       output_pic_addr_const (file, XEXP (x, 0), code);
2706       break;
2707
2708     case CONST_DOUBLE:
2709       if (GET_MODE (x) == VOIDmode)
2710         {
2711           /* We can use %d if the number is <32 bits and positive.  */
2712           if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
2713             fprintf (file, "0x%x%08x",
2714                      CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
2715           else
2716             fprintf (file, "%d", CONST_DOUBLE_LOW (x));
2717         }
2718       else
2719         /* We can't handle floating point constants;
2720            PRINT_OPERAND must handle them.  */
2721         output_operand_lossage ("floating constant misused");
2722       break;
2723
2724     case PLUS:
2725       /* Some assemblers need integer constants to appear last (eg masm).  */
2726       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
2727         {
2728           output_pic_addr_const (file, XEXP (x, 1), code);
2729           if (INTVAL (XEXP (x, 0)) >= 0)
2730             fprintf (file, "+");
2731           output_pic_addr_const (file, XEXP (x, 0), code);
2732         }
2733       else
2734         {
2735           output_pic_addr_const (file, XEXP (x, 0), code);
2736           if (INTVAL (XEXP (x, 1)) >= 0)
2737             fprintf (file, "+");
2738           output_pic_addr_const (file, XEXP (x, 1), code);
2739         }
2740       break;
2741
2742     case MINUS:
2743       output_pic_addr_const (file, XEXP (x, 0), code);
2744       fprintf (file, "-");
2745       output_pic_addr_const (file, XEXP (x, 1), code);
2746       break;
2747
2748     default:
2749       output_operand_lossage ("invalid expression as operand");
2750     }
2751 }
2752 \f
2753 /* Append the correct conditional move suffix which corresponds to CODE */
2754
2755 static void
2756 put_condition_code (code, mode, file)
2757      enum rtx_code code;
2758      enum mode_class mode;
2759      FILE * file;
2760 {
2761   if (mode == MODE_INT)
2762   switch (code)
2763     {
2764       case NE: 
2765           if (cc_prev_status.flags & CC_Z_IN_NOT_C)
2766             fputs ("b", file);
2767           else
2768             fputs ("ne", file);
2769           return;
2770       case EQ: 
2771           if (cc_prev_status.flags & CC_Z_IN_NOT_C)
2772             fputs ("ae", file);
2773           else
2774             fputs ("e", file);
2775           return;
2776       case GE: 
2777           fputs ("ge", file); return;
2778       case GT: 
2779           fputs ("g", file); return;
2780       case LE: 
2781           fputs ("le", file); return;
2782       case LT: 
2783           fputs ("l", file); return;
2784       case GEU: 
2785           fputs ("ae", file); return;
2786       case GTU: 
2787           fputs ("a", file); return;
2788       case LEU: 
2789           fputs ("be", file); return;
2790       case LTU: 
2791           fputs ("b", file); return;
2792       default: output_operand_lossage ("Invalid %%C operand");
2793     }
2794   else if (mode == MODE_FLOAT)
2795   switch (code)
2796     {
2797       case NE: 
2798           fputs ("ne", file); return;
2799       case EQ: 
2800           fputs ("e", file); return;
2801       case GE: 
2802           fputs ("nb", file); return;
2803       case GT: 
2804           fputs ("nbe", file); return;
2805       case LE: 
2806           fputs ("be", file); return;
2807       case LT: 
2808           fputs ("b", file); return;
2809       case GEU: 
2810           fputs ("nb", file); return;
2811       case GTU: 
2812           fputs ("nbe", file); return;
2813       case LEU: 
2814           fputs ("be", file); return;
2815       case LTU: 
2816           fputs ("b", file); return;
2817       default: output_operand_lossage ("Invalid %%C operand");
2818     }
2819 }
2820
2821 /* Meaning of CODE:
2822    L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
2823    C -- print opcode suffix for set/cmov insn.
2824    c -- like C, but print reversed condition
2825    F -- print opcode suffix for fcmov insn.
2826    f -- like C, but print reversed condition
2827    R -- print the prefix for register names.
2828    z -- print the opcode suffix for the size of the current operand.
2829    * -- print a star (in certain assembler syntax)
2830    w -- print the operand as if it's a "word" (HImode) even if it isn't.
2831    c -- don't print special prefixes before constant operands.
2832    J -- print the appropriate jump operand.
2833    s -- print a shift double count, followed by the assemblers argument
2834         delimiter.
2835    b -- print the QImode name of the register for the indicated operand.
2836         %b0 would print %al if operands[0] is reg 0.
2837    w --  likewise, print the HImode name of the register.
2838    k --  likewise, print the SImode name of the register.
2839    h --  print the QImode name for a "high" register, either ah, bh, ch or dh.
2840    y --  print "st(0)" instead of "st" as a register.
2841    P --  print as a PIC constant
2842 */
2843
2844 void
2845 print_operand (file, x, code)
2846      FILE *file;
2847      rtx x;
2848      int code;
2849 {
2850   if (code)
2851     {
2852       switch (code)
2853         {
2854         case '*':
2855           if (USE_STAR)
2856             putc ('*', file);
2857           return;
2858
2859         case 'L':
2860           PUT_OP_SIZE (code, 'l', file);
2861           return;
2862
2863         case 'W':
2864           PUT_OP_SIZE (code, 'w', file);
2865           return;
2866
2867         case 'B':
2868           PUT_OP_SIZE (code, 'b', file);
2869           return;
2870
2871         case 'Q':
2872           PUT_OP_SIZE (code, 'l', file);
2873           return;
2874
2875         case 'S':
2876           PUT_OP_SIZE (code, 's', file);
2877           return;
2878
2879         case 'T':
2880           PUT_OP_SIZE (code, 't', file);
2881           return;
2882
2883         case 'z':
2884           /* 387 opcodes don't get size suffixes if the operands are
2885              registers. */
2886
2887           if (STACK_REG_P (x))
2888             return;
2889
2890           /* this is the size of op from size of operand */
2891           switch (GET_MODE_SIZE (GET_MODE (x)))
2892             {
2893             case 1:
2894               PUT_OP_SIZE ('B', 'b', file);
2895               return;
2896
2897             case 2:
2898               PUT_OP_SIZE ('W', 'w', file);
2899               return;
2900
2901             case 4:
2902               if (GET_MODE (x) == SFmode)
2903                 {
2904                   PUT_OP_SIZE ('S', 's', file);
2905                   return;
2906                 }
2907               else
2908                 PUT_OP_SIZE ('L', 'l', file);
2909               return;
2910
2911             case 12:
2912                   PUT_OP_SIZE ('T', 't', file);
2913                   return;
2914
2915             case 8:
2916               if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
2917                 {
2918 #ifdef GAS_MNEMONICS
2919                   PUT_OP_SIZE ('Q', 'q', file);
2920                   return;
2921 #else
2922                   PUT_OP_SIZE ('Q', 'l', file); /* Fall through */
2923 #endif
2924                 }
2925
2926               PUT_OP_SIZE ('Q', 'l', file);
2927               return;
2928             }
2929
2930         case 'b':
2931         case 'w':
2932         case 'k':
2933         case 'h':
2934         case 'y':
2935         case 'P':
2936           break;
2937
2938         case 'J':
2939           switch (GET_CODE (x))
2940             {
2941               /* These conditions are appropriate for testing the result
2942                  of an arithmetic operation, not for a compare operation.
2943                  Cases GE, LT assume CC_NO_OVERFLOW true. All cases assume
2944                  CC_Z_IN_NOT_C false and not floating point.  */
2945             case NE:  fputs ("jne", file); return;
2946             case EQ:  fputs ("je",  file); return;
2947             case GE:  fputs ("jns", file); return;
2948             case LT:  fputs ("js",  file); return;
2949             case GEU: fputs ("jmp", file); return;
2950             case GTU: fputs ("jne",  file); return;
2951             case LEU: fputs ("je", file); return;
2952             case LTU: fputs ("#branch never",  file); return;
2953
2954             /* no matching branches for GT nor LE */
2955             }
2956           abort ();
2957
2958         case 's':
2959           if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
2960             {
2961               PRINT_OPERAND (file, x, 0);
2962               fputs (AS2C (,) + 1, file);
2963             }
2964           return;
2965
2966           /* This is used by the conditional move instructions.  */
2967         case 'C':
2968           put_condition_code (GET_CODE (x), MODE_INT, file);
2969           return;
2970
2971           /* like above, but reverse condition */
2972         case 'c':
2973           put_condition_code (reverse_condition (GET_CODE (x)), MODE_INT, file);
2974           return;
2975
2976         case 'F':
2977           put_condition_code (GET_CODE (x), MODE_FLOAT, file);
2978           return;
2979
2980           /* like above, but reverse condition */
2981         case 'f':
2982           put_condition_code (reverse_condition (GET_CODE (x)),
2983                               MODE_FLOAT, file);
2984           return;
2985
2986         default:
2987           {
2988             char str[50];
2989
2990             sprintf (str, "invalid operand code `%c'", code);
2991             output_operand_lossage (str);
2992           }
2993         }
2994     }
2995   if (GET_CODE (x) == REG)
2996     {
2997       PRINT_REG (x, code, file);
2998     }
2999   else if (GET_CODE (x) == MEM)
3000     {
3001       PRINT_PTR (x, file);
3002       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
3003         {
3004           if (flag_pic)
3005             output_pic_addr_const (file, XEXP (x, 0), code);
3006           else
3007             output_addr_const (file, XEXP (x, 0));
3008         }
3009       else
3010         output_address (XEXP (x, 0));
3011     }
3012   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
3013     {
3014       REAL_VALUE_TYPE r; long l;
3015       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3016       REAL_VALUE_TO_TARGET_SINGLE (r, l);
3017       PRINT_IMMED_PREFIX (file);
3018       fprintf (file, "0x%x", l);
3019     }
3020  /* These float cases don't actually occur as immediate operands. */
3021  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
3022     {
3023       REAL_VALUE_TYPE r; char dstr[30];
3024       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3025       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
3026       fprintf (file, "%s", dstr);
3027     }
3028   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
3029     {
3030       REAL_VALUE_TYPE r; char dstr[30];
3031       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
3032       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
3033       fprintf (file, "%s", dstr);
3034     }
3035   else 
3036     {
3037       if (code != 'P')
3038         {
3039           if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
3040             PRINT_IMMED_PREFIX (file);
3041           else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
3042                    || GET_CODE (x) == LABEL_REF)
3043             PRINT_OFFSET_PREFIX (file);
3044         }
3045       if (flag_pic)
3046         output_pic_addr_const (file, x, code);
3047       else
3048         output_addr_const (file, x);
3049     }
3050 }
3051 \f
3052 /* Print a memory operand whose address is ADDR.  */
3053
3054 void
3055 print_operand_address (file, addr)
3056      FILE *file;
3057      register rtx addr;
3058 {
3059   register rtx reg1, reg2, breg, ireg;
3060   rtx offset;
3061
3062   switch (GET_CODE (addr))
3063     {
3064     case REG:
3065       ADDR_BEG (file);
3066       fprintf (file, "%se", RP);
3067       fputs (hi_reg_name[REGNO (addr)], file);
3068       ADDR_END (file);
3069       break;
3070
3071     case PLUS:
3072       reg1 = 0;
3073       reg2 = 0;
3074       ireg = 0;
3075       breg = 0;
3076       offset = 0;
3077       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
3078         {
3079           offset = XEXP (addr, 0);
3080           addr = XEXP (addr, 1);
3081         }
3082       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
3083         {
3084           offset = XEXP (addr, 1);
3085           addr = XEXP (addr, 0);
3086         }
3087       if (GET_CODE (addr) != PLUS) ;
3088       else if (GET_CODE (XEXP (addr, 0)) == MULT)
3089         {
3090           reg1 = XEXP (addr, 0);
3091           addr = XEXP (addr, 1);
3092         }
3093       else if (GET_CODE (XEXP (addr, 1)) == MULT)
3094         {
3095           reg1 = XEXP (addr, 1);
3096           addr = XEXP (addr, 0);
3097         }
3098       else if (GET_CODE (XEXP (addr, 0)) == REG)
3099         {
3100           reg1 = XEXP (addr, 0);
3101           addr = XEXP (addr, 1);
3102         }
3103       else if (GET_CODE (XEXP (addr, 1)) == REG)
3104         {
3105           reg1 = XEXP (addr, 1);
3106           addr = XEXP (addr, 0);
3107         }
3108       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
3109         {
3110           if (reg1 == 0) reg1 = addr;
3111           else reg2 = addr;
3112           addr = 0;
3113         }
3114       if (offset != 0)
3115         {
3116           if (addr != 0) abort ();
3117           addr = offset;
3118         }
3119       if ((reg1 && GET_CODE (reg1) == MULT)
3120           || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
3121         {
3122           breg = reg2;
3123           ireg = reg1;
3124         }
3125       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
3126         {
3127           breg = reg1;
3128           ireg = reg2;
3129         }
3130
3131       if (ireg != 0 || breg != 0)
3132         {
3133           int scale = 1;
3134
3135           if (addr != 0)
3136             {
3137               if (flag_pic)
3138                 output_pic_addr_const (file, addr, 0);
3139
3140               else if (GET_CODE (addr) == LABEL_REF)
3141                 output_asm_label (addr);
3142
3143               else
3144                 output_addr_const (file, addr);
3145             }
3146
3147           if (ireg != 0 && GET_CODE (ireg) == MULT)
3148             {
3149               scale = INTVAL (XEXP (ireg, 1));
3150               ireg = XEXP (ireg, 0);
3151             }
3152
3153           /* The stack pointer can only appear as a base register,
3154              never an index register, so exchange the regs if it is wrong. */
3155
3156           if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
3157             {
3158               rtx tmp;
3159
3160               tmp = breg;
3161               breg = ireg;
3162               ireg = tmp;
3163             }
3164
3165           /* output breg+ireg*scale */
3166           PRINT_B_I_S (breg, ireg, scale, file);
3167           break;
3168         }
3169
3170     case MULT:
3171       {
3172         int scale;
3173         if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
3174           {
3175             scale = INTVAL (XEXP (addr, 0));
3176             ireg = XEXP (addr, 1);
3177           }
3178         else
3179           {
3180             scale = INTVAL (XEXP (addr, 1));
3181             ireg = XEXP (addr, 0);
3182           }
3183         output_addr_const (file, const0_rtx);
3184         PRINT_B_I_S ((rtx) 0, ireg, scale, file);
3185       }
3186       break;
3187
3188     default:
3189       if (GET_CODE (addr) == CONST_INT
3190           && INTVAL (addr) < 0x8000
3191           && INTVAL (addr) >= -0x8000)
3192         fprintf (file, "%d", INTVAL (addr));
3193       else
3194         {
3195           if (flag_pic)
3196             output_pic_addr_const (file, addr, 0);
3197           else
3198             output_addr_const (file, addr);
3199         }
3200     }
3201 }
3202 \f
3203 /* Set the cc_status for the results of an insn whose pattern is EXP.
3204    On the 80386, we assume that only test and compare insns, as well
3205    as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT,
3206    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
3207    Also, we assume that jumps, moves and sCOND don't affect the condition
3208    codes.  All else clobbers the condition codes, by assumption.
3209
3210    We assume that ALL integer add, minus, etc. instructions effect the
3211    condition codes.  This MUST be consistent with i386.md.
3212
3213    We don't record any float test or compare - the redundant test &
3214    compare check in final.c does not handle stack-like regs correctly. */
3215
3216 void
3217 notice_update_cc (exp)
3218      rtx exp;
3219 {
3220   if (GET_CODE (exp) == SET)
3221     {
3222       /* Jumps do not alter the cc's.  */
3223       if (SET_DEST (exp) == pc_rtx)
3224         return;
3225 #ifdef IS_STACK_MODE
3226       /* Moving into a memory of stack_mode may have been moved
3227          in between the use and set of cc0 by loop_spl(). So
3228          old value of cc.status must be retained */
3229       if(GET_CODE(SET_DEST(exp))==MEM 
3230          && IS_STACK_MODE(GET_MODE(SET_DEST(exp))))
3231         {
3232           return;
3233         }
3234 #endif
3235       /* Moving register or memory into a register:
3236          it doesn't alter the cc's, but it might invalidate
3237          the RTX's which we remember the cc's came from.
3238          (Note that moving a constant 0 or 1 MAY set the cc's).  */
3239       if (REG_P (SET_DEST (exp))
3240           && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
3241               || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
3242         {
3243           if (cc_status.value1
3244               && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
3245             cc_status.value1 = 0;
3246           if (cc_status.value2
3247               && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
3248             cc_status.value2 = 0;
3249           return;
3250         }
3251       /* Moving register into memory doesn't alter the cc's.
3252          It may invalidate the RTX's which we remember the cc's came from.  */
3253       if (GET_CODE (SET_DEST (exp)) == MEM
3254           && (REG_P (SET_SRC (exp))
3255               || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
3256         {
3257           if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
3258               || reg_mentioned_p (SET_DEST (exp), cc_status.value1))
3259             cc_status.value1 = 0;
3260           if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM
3261               || reg_mentioned_p (SET_DEST (exp), cc_status.value2))
3262             cc_status.value2 = 0;
3263           return;
3264         }
3265       /* Function calls clobber the cc's.  */
3266       else if (GET_CODE (SET_SRC (exp)) == CALL)
3267         {
3268           CC_STATUS_INIT;
3269           return;
3270         }
3271       /* Tests and compares set the cc's in predictable ways.  */
3272       else if (SET_DEST (exp) == cc0_rtx)
3273         {
3274           CC_STATUS_INIT;
3275           cc_status.value1 = SET_SRC (exp);
3276           return;
3277         }
3278       /* Certain instructions effect the condition codes. */
3279       else if (GET_MODE (SET_SRC (exp)) == SImode
3280                || GET_MODE (SET_SRC (exp)) == HImode
3281                || GET_MODE (SET_SRC (exp)) == QImode)
3282         switch (GET_CODE (SET_SRC (exp)))
3283           {
3284           case ASHIFTRT: case LSHIFTRT:
3285           case ASHIFT:
3286             /* Shifts on the 386 don't set the condition codes if the
3287                shift count is zero. */
3288             if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
3289               {
3290                 CC_STATUS_INIT;
3291                 break;
3292               }
3293             /* We assume that the CONST_INT is non-zero (this rtx would
3294                have been deleted if it were zero. */
3295
3296           case PLUS: case MINUS: case NEG:
3297           case AND: case IOR: case XOR:
3298             cc_status.flags = CC_NO_OVERFLOW;
3299             cc_status.value1 = SET_SRC (exp);
3300             cc_status.value2 = SET_DEST (exp);
3301             break;
3302
3303           default:
3304             CC_STATUS_INIT;
3305           }
3306       else
3307         {
3308           CC_STATUS_INIT;
3309         }
3310     }
3311   else if (GET_CODE (exp) == PARALLEL
3312            && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
3313     {
3314       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
3315         return;
3316       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
3317         {
3318           CC_STATUS_INIT;
3319           if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
3320             cc_status.flags |= CC_IN_80387;
3321           else
3322             cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
3323           return;
3324         }
3325       CC_STATUS_INIT;
3326     }
3327   else
3328     {
3329       CC_STATUS_INIT;
3330     }
3331 }
3332 \f
3333 /* Split one or more DImode RTL references into pairs of SImode
3334    references.  The RTL can be REG, offsettable MEM, integer constant, or
3335    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
3336    split and "num" is its length.  lo_half and hi_half are output arrays
3337    that parallel "operands". */
3338
3339 void
3340 split_di (operands, num, lo_half, hi_half)
3341      rtx operands[];
3342      int num;
3343      rtx lo_half[], hi_half[];
3344 {
3345   while (num--)
3346     {
3347       if (GET_CODE (operands[num]) == REG)
3348         {
3349           lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
3350           hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
3351         }
3352       else if (CONSTANT_P (operands[num]))
3353         {
3354           split_double (operands[num], &lo_half[num], &hi_half[num]);
3355         }
3356       else if (offsettable_memref_p (operands[num]))
3357         {
3358           lo_half[num] = operands[num];
3359           hi_half[num] = adj_offsettable_operand (operands[num], 4);
3360         }
3361       else
3362         abort();
3363     }
3364 }
3365 \f
3366 /* Return 1 if this is a valid binary operation on a 387.
3367    OP is the expression matched, and MODE is its mode. */
3368
3369 int
3370 binary_387_op (op, mode)
3371     register rtx op;
3372     enum machine_mode mode;
3373 {
3374   if (mode != VOIDmode && mode != GET_MODE (op))
3375     return 0;
3376
3377   switch (GET_CODE (op))
3378     {
3379     case PLUS:
3380     case MINUS:
3381     case MULT:
3382     case DIV:
3383       return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
3384
3385     default:
3386       return 0;
3387     }
3388 }
3389
3390 \f
3391 /* Return 1 if this is a valid shift or rotate operation on a 386.
3392    OP is the expression matched, and MODE is its mode. */
3393
3394 int
3395 shift_op (op, mode)
3396     register rtx op;
3397     enum machine_mode mode;
3398 {
3399   rtx operand = XEXP (op, 0);
3400
3401   if (mode != VOIDmode && mode != GET_MODE (op))
3402     return 0;
3403
3404   if (GET_MODE (operand) != GET_MODE (op)
3405       || GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
3406     return 0;
3407
3408   return (GET_CODE (op) == ASHIFT
3409           || GET_CODE (op) == ASHIFTRT
3410           || GET_CODE (op) == LSHIFTRT
3411           || GET_CODE (op) == ROTATE
3412           || GET_CODE (op) == ROTATERT);
3413 }
3414
3415 /* Return 1 if OP is COMPARE rtx with mode VOIDmode.
3416    MODE is not used.  */
3417
3418 int
3419 VOIDmode_compare_op (op, mode)
3420     register rtx op;
3421     enum machine_mode mode;
3422 {
3423   return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
3424 }
3425 \f
3426 /* Output code to perform a 387 binary operation in INSN, one of PLUS,
3427    MINUS, MULT or DIV.  OPERANDS are the insn operands, where operands[3]
3428    is the expression of the binary operation.  The output may either be
3429    emitted here, or returned to the caller, like all output_* functions.
3430
3431    There is no guarantee that the operands are the same mode, as they
3432    might be within FLOAT or FLOAT_EXTEND expressions. */
3433
3434 char *
3435 output_387_binary_op (insn, operands)
3436      rtx insn;
3437      rtx *operands;
3438 {
3439   rtx temp;
3440   char *base_op;
3441   static char buf[100];
3442
3443   switch (GET_CODE (operands[3]))
3444     {
3445     case PLUS:
3446       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
3447           || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
3448         base_op = "fiadd";
3449       else
3450         base_op = "fadd";
3451       break;
3452
3453     case MINUS:
3454       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
3455           || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
3456         base_op = "fisub";
3457       else
3458         base_op = "fsub";
3459       break;
3460
3461     case MULT:
3462       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
3463           || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
3464         base_op = "fimul";
3465       else
3466         base_op = "fmul";
3467       break;
3468
3469     case DIV:
3470       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
3471           || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
3472         base_op = "fidiv";
3473       else
3474         base_op = "fdiv";
3475       break;
3476
3477     default:
3478       abort ();
3479     }
3480
3481   strcpy (buf, base_op);
3482
3483   switch (GET_CODE (operands[3]))
3484     {
3485     case MULT:
3486     case PLUS:
3487       if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
3488         {
3489           temp = operands[2];
3490           operands[2] = operands[1];
3491           operands[1] = temp;
3492         }
3493
3494       if (GET_CODE (operands[2]) == MEM)
3495         return strcat (buf, AS1 (%z2,%2));
3496
3497       if (NON_STACK_REG_P (operands[1]))
3498         {
3499           output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
3500           RET;
3501         }
3502       else if (NON_STACK_REG_P (operands[2]))
3503         {
3504           output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
3505           RET;
3506         }
3507
3508       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
3509         return strcat (buf, AS2 (p,%2,%0));
3510
3511       if (STACK_TOP_P (operands[0]))
3512         return strcat (buf, AS2C (%y2,%0));
3513       else
3514         return strcat (buf, AS2C (%2,%0));
3515
3516     case MINUS:
3517     case DIV:
3518       if (GET_CODE (operands[1]) == MEM)
3519         return strcat (buf, AS1 (r%z1,%1));
3520
3521       if (GET_CODE (operands[2]) == MEM)
3522         return strcat (buf, AS1 (%z2,%2));
3523
3524       if (NON_STACK_REG_P (operands[1]))
3525         {
3526           output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
3527           RET;
3528         }
3529       else if (NON_STACK_REG_P (operands[2]))
3530         {
3531           output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
3532           RET;
3533         }
3534
3535       if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
3536         abort ();
3537
3538       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
3539         return strcat (buf, AS2 (rp,%2,%0));
3540
3541       if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
3542         return strcat (buf, AS2 (p,%1,%0));
3543
3544       if (STACK_TOP_P (operands[0]))
3545         {
3546           if (STACK_TOP_P (operands[1]))
3547             return strcat (buf, AS2C (%y2,%0));
3548           else
3549             return strcat (buf, AS2 (r,%y1,%0));
3550         }
3551       else if (STACK_TOP_P (operands[1]))
3552         return strcat (buf, AS2C (%1,%0));
3553       else
3554         return strcat (buf, AS2 (r,%2,%0));
3555
3556     default:
3557       abort ();
3558     }
3559 }
3560 \f
3561 /* Output code for INSN to convert a float to a signed int.  OPERANDS
3562    are the insn operands.  The output may be SFmode or DFmode and the
3563    input operand may be SImode or DImode.  As a special case, make sure
3564    that the 387 stack top dies if the output mode is DImode, because the
3565    hardware requires this.  */
3566
3567 char *
3568 output_fix_trunc (insn, operands)
3569      rtx insn;
3570      rtx *operands;
3571 {
3572   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
3573   rtx xops[2];
3574
3575   if (! STACK_TOP_P (operands[1]) ||
3576       (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
3577     abort ();
3578
3579   xops[0] = GEN_INT (12);
3580   xops[1] = operands[4];
3581
3582   output_asm_insn (AS1 (fnstc%W2,%2), operands);
3583   output_asm_insn (AS2 (mov%L2,%2,%4), operands);
3584   output_asm_insn (AS2 (mov%B1,%0,%h1), xops);
3585   output_asm_insn (AS2 (mov%L4,%4,%3), operands);
3586   output_asm_insn (AS1 (fldc%W3,%3), operands);
3587
3588   if (NON_STACK_REG_P (operands[0]))
3589     output_to_reg (operands[0], stack_top_dies);
3590   else if (GET_CODE (operands[0]) == MEM)
3591     {
3592       if (stack_top_dies)
3593         output_asm_insn (AS1 (fistp%z0,%0), operands);
3594       else
3595         output_asm_insn (AS1 (fist%z0,%0), operands);
3596     }
3597   else
3598     abort ();
3599
3600   return AS1 (fldc%W2,%2);
3601 }
3602 \f
3603 /* Output code for INSN to compare OPERANDS.  The two operands might
3604    not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
3605    expression.  If the compare is in mode CCFPEQmode, use an opcode that
3606    will not fault if a qNaN is present. */
3607
3608 char *
3609 output_float_compare (insn, operands)
3610      rtx insn;
3611      rtx *operands;
3612 {
3613   int stack_top_dies;
3614   rtx body = XVECEXP (PATTERN (insn), 0, 0);
3615   int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
3616   rtx tmp;
3617
3618   if (TARGET_CMOVE && STACK_REG_P (operands[1]))
3619     {
3620       cc_status.flags |= CC_FCOMI;
3621       cc_prev_status.flags &= ~CC_TEST_AX;
3622     }
3623
3624   if (! STACK_TOP_P (operands[0]))
3625     {
3626       tmp = operands[0];
3627       operands[0] = operands[1];
3628       operands[1] = tmp;
3629       cc_status.flags |= CC_REVERSED;
3630     }
3631     
3632   if (! STACK_TOP_P (operands[0]))
3633     abort ();
3634
3635   stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
3636
3637   if (STACK_REG_P (operands[1])
3638       && stack_top_dies
3639       && find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
3640       && REGNO (operands[1]) != FIRST_STACK_REG)
3641     {
3642       /* If both the top of the 387 stack dies, and the other operand
3643          is also a stack register that dies, then this must be a
3644          `fcompp' float compare */
3645
3646       if (unordered_compare)
3647         output_asm_insn ("fucompp", operands);
3648       else
3649         output_asm_insn ("fcompp", operands);
3650     }
3651   else
3652     {
3653       static char buf[100];
3654
3655       /* Decide if this is the integer or float compare opcode, or the
3656          unordered float compare. */
3657
3658       if (unordered_compare)
3659         strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
3660       else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
3661         strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
3662       else
3663         strcpy (buf, "ficom");
3664
3665       /* Modify the opcode if the 387 stack is to be popped. */
3666
3667       if (stack_top_dies)
3668         strcat (buf, "p");
3669
3670       if (NON_STACK_REG_P (operands[1]))
3671         output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
3672       else if (cc_status.flags & CC_FCOMI) 
3673         {
3674           rtx xops[3];
3675           
3676           xops[0] = operands[0];
3677           xops[1] = operands[1];
3678           xops[2] = operands[0];
3679           
3680           output_asm_insn (strcat (buf, AS2 (%z1,%y1,%2)), xops);
3681           RET;
3682         }
3683       else
3684         output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
3685     }
3686
3687   /* Now retrieve the condition code. */
3688
3689   return output_fp_cc0_set (insn);
3690 }
3691 \f
3692 /* Output opcodes to transfer the results of FP compare or test INSN
3693    from the FPU to the CPU flags.  If TARGET_IEEE_FP, ensure that if the
3694    result of the compare or test is unordered, no comparison operator
3695    succeeds except NE.  Return an output template, if any.  */
3696
3697 char *
3698 output_fp_cc0_set (insn)
3699      rtx insn;
3700 {
3701   rtx xops[3];
3702   rtx unordered_label;
3703   rtx next;
3704   enum rtx_code code;
3705
3706   xops[0] = gen_rtx (REG, HImode, 0);
3707   output_asm_insn (AS1 (fnsts%W0,%0), xops);
3708
3709   if (! TARGET_IEEE_FP)
3710     {
3711       if (!(cc_status.flags & CC_REVERSED))
3712         {
3713           next = next_cc0_user (insn);
3714         
3715           if (GET_CODE (next) == JUMP_INSN
3716               && GET_CODE (PATTERN (next)) == SET
3717               && SET_DEST (PATTERN (next)) == pc_rtx
3718               && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
3719             {
3720               code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
3721             }
3722           else if (GET_CODE (PATTERN (next)) == SET)
3723             {
3724               code = GET_CODE (SET_SRC (PATTERN (next)));
3725             }
3726           else
3727             {
3728               return "sahf";
3729             }
3730           if (code == GT || code == LT || code == EQ || code == NE
3731               || code == LE || code == GE)
3732             { /* We will test eax directly */
3733               cc_status.flags |= CC_TEST_AX;
3734               RET;
3735             }
3736         }
3737       return "sahf";
3738     }
3739
3740   next = next_cc0_user (insn);
3741   if (next == NULL_RTX)
3742     abort ();
3743
3744   if (GET_CODE (next) == JUMP_INSN
3745       && GET_CODE (PATTERN (next)) == SET
3746       && SET_DEST (PATTERN (next)) == pc_rtx
3747       && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
3748     {
3749       code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
3750     }
3751   else if (GET_CODE (PATTERN (next)) == SET)
3752     {
3753       if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
3754         code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
3755       else code = GET_CODE (SET_SRC (PATTERN (next)));
3756     }
3757   else if (GET_CODE (PATTERN (next)) == PARALLEL
3758            && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET)
3759     {
3760       if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE)
3761           code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0));
3762       else code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0)));
3763     }
3764   else
3765     abort ();
3766
3767   xops[0] = gen_rtx (REG, QImode, 0);
3768
3769   switch (code)
3770     {
3771     case GT:
3772       xops[1] = GEN_INT (0x45);
3773       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3774       /* je label */
3775       break;
3776
3777     case LT:
3778       xops[1] = GEN_INT (0x45);
3779       xops[2] = GEN_INT (0x01);
3780       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3781       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
3782       /* je label */
3783       break;
3784
3785     case GE:
3786       xops[1] = GEN_INT (0x05);
3787       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3788       /* je label */
3789       break;
3790
3791     case LE:
3792       xops[1] = GEN_INT (0x45);
3793       xops[2] = GEN_INT (0x40);
3794       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3795       output_asm_insn (AS1 (dec%B0,%h0), xops);
3796       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
3797       /* jb label */
3798       break;
3799
3800     case EQ:
3801       xops[1] = GEN_INT (0x45);
3802       xops[2] = GEN_INT (0x40);
3803       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3804       output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
3805       /* je label */
3806       break;
3807
3808     case NE:
3809       xops[1] = GEN_INT (0x44);
3810       xops[2] = GEN_INT (0x40);
3811       output_asm_insn (AS2 (and%B0,%1,%h0), xops);
3812       output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
3813       /* jne label */
3814       break;
3815
3816     case GTU:
3817     case LTU:
3818     case GEU:
3819     case LEU:
3820     default:
3821       abort ();
3822     }
3823   RET;
3824 }
3825 \f
3826 #define MAX_386_STACK_LOCALS 2
3827
3828 static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
3829
3830 /* Define the structure for the machine field in struct function.  */
3831 struct machine_function
3832 {
3833   rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
3834 };
3835
3836 /* Functions to save and restore i386_stack_locals.
3837    These will be called, via pointer variables,
3838    from push_function_context and pop_function_context.  */
3839
3840 void
3841 save_386_machine_status (p)
3842      struct function *p;
3843 {
3844   p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals);
3845   bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
3846          sizeof i386_stack_locals);
3847 }
3848
3849 void
3850 restore_386_machine_status (p)
3851      struct function *p;
3852 {
3853   bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
3854          sizeof i386_stack_locals);
3855   free (p->machine);
3856 }
3857
3858 /* Clear stack slot assignments remembered from previous functions.
3859    This is called from INIT_EXPANDERS once before RTL is emitted for each
3860    function.  */
3861
3862 void
3863 clear_386_stack_locals ()
3864 {
3865   enum machine_mode mode;
3866   int n;
3867
3868   for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
3869        mode = (enum machine_mode) ((int) mode + 1))
3870     for (n = 0; n < MAX_386_STACK_LOCALS; n++)
3871       i386_stack_locals[(int) mode][n] = NULL_RTX;
3872
3873   /* Arrange to save and restore i386_stack_locals around nested functions.  */
3874   save_machine_status = save_386_machine_status;
3875   restore_machine_status = restore_386_machine_status;
3876 }
3877
3878 /* Return a MEM corresponding to a stack slot with mode MODE.
3879    Allocate a new slot if necessary.
3880
3881    The RTL for a function can have several slots available: N is
3882    which slot to use.  */
3883
3884 rtx
3885 assign_386_stack_local (mode, n)
3886      enum machine_mode mode;
3887      int n;
3888 {
3889   if (n < 0 || n >= MAX_386_STACK_LOCALS)
3890     abort ();
3891
3892   if (i386_stack_locals[(int) mode][n] == NULL_RTX)
3893     i386_stack_locals[(int) mode][n]
3894       = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
3895
3896   return i386_stack_locals[(int) mode][n];
3897 }
3898
3899 \f
3900 int is_mul(op,mode)
3901     register rtx op;
3902     enum machine_mode mode;
3903 {
3904   return (GET_CODE (op) == MULT);
3905 }
3906
3907 int is_div(op,mode)
3908     register rtx op;
3909     enum machine_mode mode;
3910 {
3911   return (GET_CODE (op) == DIV);
3912 }
3913
3914 \f
3915 #ifdef NOTYET
3916 /* Create a new copy of an rtx.
3917    Recursively copies the operands of the rtx,
3918    except for those few rtx codes that are sharable.
3919    Doesn't share CONST  */
3920
3921 rtx
3922 copy_all_rtx (orig)
3923      register rtx orig;
3924 {
3925   register rtx copy;
3926   register int i, j;
3927   register RTX_CODE code;
3928   register char *format_ptr;
3929
3930   code = GET_CODE (orig);
3931
3932   switch (code)
3933     {
3934     case REG:
3935     case QUEUED:
3936     case CONST_INT:
3937     case CONST_DOUBLE:
3938     case SYMBOL_REF:
3939     case CODE_LABEL:
3940     case PC:
3941     case CC0:
3942     case SCRATCH:
3943       /* SCRATCH must be shared because they represent distinct values. */
3944       return orig;
3945
3946 #if 0
3947     case CONST:
3948       /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
3949          a LABEL_REF, it isn't sharable.  */
3950       if (GET_CODE (XEXP (orig, 0)) == PLUS
3951           && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
3952           && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
3953         return orig;
3954       break;
3955 #endif
3956       /* A MEM with a constant address is not sharable.  The problem is that
3957          the constant address may need to be reloaded.  If the mem is shared,
3958          then reloading one copy of this mem will cause all copies to appear
3959          to have been reloaded.  */
3960     }
3961
3962   copy = rtx_alloc (code);
3963   PUT_MODE (copy, GET_MODE (orig));
3964   copy->in_struct = orig->in_struct;
3965   copy->volatil = orig->volatil;
3966   copy->unchanging = orig->unchanging;
3967   copy->integrated = orig->integrated;
3968   /* intel1 */
3969   copy->is_spill_rtx = orig->is_spill_rtx;
3970   
3971   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
3972
3973   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
3974     {
3975       switch (*format_ptr++)
3976         {
3977         case 'e':
3978           XEXP (copy, i) = XEXP (orig, i);
3979           if (XEXP (orig, i) != NULL)
3980             XEXP (copy, i) = copy_rtx (XEXP (orig, i));
3981           break;
3982
3983         case '0':
3984         case 'u':
3985           XEXP (copy, i) = XEXP (orig, i);
3986           break;
3987
3988         case 'E':
3989         case 'V':
3990           XVEC (copy, i) = XVEC (orig, i);
3991           if (XVEC (orig, i) != NULL)
3992             {
3993               XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
3994               for (j = 0; j < XVECLEN (copy, i); j++)
3995                 XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
3996             }
3997           break;
3998
3999         case 'w':
4000           XWINT (copy, i) = XWINT (orig, i);
4001           break;
4002
4003         case 'i':
4004           XINT (copy, i) = XINT (orig, i);
4005           break;
4006
4007         case 's':
4008         case 'S':
4009           XSTR (copy, i) = XSTR (orig, i);
4010           break;
4011
4012         default:
4013           abort ();
4014         }
4015     }
4016   return copy;
4017 }
4018
4019 \f
4020 /* try to rewrite a memory address to make it valid */
4021 void 
4022 rewrite_address (mem_rtx)
4023      rtx mem_rtx;
4024 {
4025   rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx;
4026   int scale = 1;
4027   int offset_adjust = 0;
4028   int was_only_offset = 0;
4029   rtx mem_addr = XEXP (mem_rtx, 0);
4030   char *storage = (char *) oballoc (0);
4031   int in_struct = 0;
4032   int is_spill_rtx = 0;
4033
4034   in_struct = MEM_IN_STRUCT_P (mem_rtx);
4035   is_spill_rtx = RTX_IS_SPILL_P (mem_rtx);
4036
4037   if (GET_CODE (mem_addr) == PLUS &&
4038       GET_CODE (XEXP (mem_addr, 1)) == PLUS &&
4039       GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG)
4040     {                           /* this part is utilized by the combiner */
4041       ret_rtx =
4042         gen_rtx (PLUS, GET_MODE (mem_addr),
4043                  gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)),
4044                           XEXP (mem_addr, 0),
4045                           XEXP (XEXP (mem_addr, 1), 0)),
4046                  XEXP (XEXP (mem_addr, 1), 1));
4047       if (memory_address_p (GET_MODE (mem_rtx), ret_rtx))
4048         {
4049           XEXP (mem_rtx, 0) = ret_rtx;
4050           RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx;
4051           return;
4052         }
4053       obfree (storage);
4054     }
4055
4056   /* this part is utilized by loop.c */
4057   /* If the address contains PLUS (reg,const) and this pattern is invalid
4058      in this case - try to rewrite the address to make it valid  intel1
4059   */
4060   storage = (char *) oballoc (0);
4061   index_rtx = base_rtx = offset_rtx = NULL;
4062   /* find the base index and offset elements of the memory address */
4063   if (GET_CODE (mem_addr) == PLUS)
4064     {
4065       if (GET_CODE (XEXP (mem_addr, 0)) == REG)
4066         {
4067           if (GET_CODE (XEXP (mem_addr, 1)) == REG)
4068             {
4069               base_rtx = XEXP (mem_addr, 1);
4070               index_rtx = XEXP (mem_addr, 0);
4071             }
4072           else
4073             {
4074               base_rtx = XEXP (mem_addr, 0);
4075               offset_rtx = XEXP (mem_addr, 1);
4076             }
4077         }
4078       else if (GET_CODE (XEXP (mem_addr, 0)) == MULT)
4079         {
4080           index_rtx = XEXP (mem_addr, 0);
4081           if (GET_CODE (XEXP (mem_addr, 1)) == REG)
4082             {
4083               base_rtx = XEXP (mem_addr, 1);
4084             }
4085           else
4086             {
4087               offset_rtx = XEXP (mem_addr, 1);
4088             }
4089         }
4090       else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS)
4091         {
4092           /* intel1 */
4093           if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS &&
4094               GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT &&
4095               GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0)) == REG &&
4096               GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1)) == CONST_INT &&
4097               GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1)) == CONST_INT &&
4098               GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG &&
4099               GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF)
4100             {
4101               index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0);
4102               offset_rtx = XEXP (mem_addr, 1);
4103               base_rtx = XEXP (XEXP (mem_addr, 0), 1);
4104               offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1));
4105             }
4106           else
4107             {
4108               offset_rtx = XEXP (mem_addr, 1);
4109               index_rtx = XEXP (XEXP (mem_addr, 0), 0);
4110               base_rtx = XEXP (XEXP (mem_addr, 0), 1);
4111             }
4112         }
4113       else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT)
4114         {
4115           was_only_offset = 1;
4116           index_rtx = NULL;
4117           base_rtx = NULL;
4118           offset_rtx = XEXP (mem_addr, 1);
4119           offset_adjust = INTVAL (XEXP (mem_addr, 0));
4120           if (offset_adjust == 0)
4121             {
4122               XEXP (mem_rtx, 0) = offset_rtx;
4123               RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
4124               return;
4125             }
4126         }
4127       else
4128         {
4129           obfree (storage);
4130           return;
4131         }
4132     }
4133   else if (GET_CODE (mem_addr) == MULT)
4134     {
4135       index_rtx = mem_addr;
4136     }
4137   else
4138     {
4139       obfree (storage);
4140       return;
4141     }
4142   if (index_rtx && GET_CODE (index_rtx) == MULT)
4143     {
4144       if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT)
4145         {
4146           obfree (storage);
4147           return;
4148         }
4149       scale_rtx = XEXP (index_rtx, 1);
4150       scale = INTVAL (scale_rtx);
4151       index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
4152     }
4153   /* now find which of the elements are invalid and try to fix them */
4154   if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL)
4155     {
4156       offset_adjust = INTVAL (index_rtx) * scale;
4157       if (offset_rtx && GET_CODE (offset_rtx) == CONST &&
4158           GET_CODE (XEXP (offset_rtx, 0)) == PLUS)
4159         {
4160           if (GET_CODE (XEXP (XEXP (offset_rtx, 0), 0)) == SYMBOL_REF &&
4161               GET_CODE (XEXP (XEXP (offset_rtx, 0), 1)) == CONST_INT)
4162             {
4163               offset_rtx = copy_all_rtx (offset_rtx);
4164               XEXP (XEXP (offset_rtx, 0), 1) =
4165                 gen_rtx (CONST_INT, 0, INTVAL (XEXP (XEXP (offset_rtx, 0), 1)) + offset_adjust);
4166               if (!CONSTANT_P (offset_rtx))
4167                 {
4168                   obfree (storage);
4169                   return;
4170                 }
4171             }
4172         }
4173       else if (offset_rtx && GET_CODE (offset_rtx) == SYMBOL_REF)
4174         {
4175           offset_rtx =
4176             gen_rtx (CONST, GET_MODE (offset_rtx),
4177                      gen_rtx (PLUS, GET_MODE (offset_rtx),
4178                               offset_rtx,
4179                               gen_rtx (CONST_INT, 0, offset_adjust)));
4180           if (!CONSTANT_P (offset_rtx))
4181             {
4182               obfree (storage);
4183               return;
4184             }
4185         }
4186       else if (offset_rtx && GET_CODE (offset_rtx) == CONST_INT)
4187         {
4188           offset_rtx = gen_rtx (CONST_INT, 0, INTVAL (offset_rtx) + offset_adjust);
4189         }
4190       else if (!offset_rtx)
4191         {
4192           offset_rtx = gen_rtx (CONST_INT, 0, 0);
4193         }
4194       RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
4195       XEXP (mem_rtx, 0) = offset_rtx;
4196       return;
4197     }
4198   if (base_rtx && GET_CODE (base_rtx) == PLUS &&
4199       GET_CODE (XEXP (base_rtx, 0)) == REG &&
4200       GET_CODE (XEXP (base_rtx, 1)) == CONST_INT)
4201     {
4202       offset_adjust += INTVAL (XEXP (base_rtx, 1));
4203       base_rtx = copy_all_rtx (XEXP (base_rtx, 0));
4204     }
4205   else if (base_rtx && GET_CODE (base_rtx) == CONST_INT)
4206     {
4207       offset_adjust += INTVAL (base_rtx);
4208       base_rtx = NULL;
4209     }
4210   if (index_rtx && GET_CODE (index_rtx) == PLUS &&
4211       GET_CODE (XEXP (index_rtx, 0)) == REG &&
4212       GET_CODE (XEXP (index_rtx, 1)) == CONST_INT)
4213     {
4214       offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale;
4215       index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
4216     }
4217   if (index_rtx)
4218     {
4219       if (!LEGITIMATE_INDEX_P (index_rtx)
4220       && !(index_rtx == stack_pointer_rtx && scale == 1 && base_rtx == NULL))
4221         {
4222           obfree (storage);
4223           return;
4224         }
4225     }
4226   if (base_rtx)
4227     {
4228       if (!LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG)
4229         {
4230           obfree (storage);
4231           return;
4232         }
4233     }
4234   if (offset_adjust != 0)
4235     {
4236       if (offset_rtx)
4237         {
4238           if (GET_CODE (offset_rtx) == CONST &&
4239               GET_CODE (XEXP (offset_rtx, 0)) == PLUS)
4240             {
4241               if (GET_CODE (XEXP (XEXP (offset_rtx, 0), 0)) == SYMBOL_REF &&
4242                   GET_CODE (XEXP (XEXP (offset_rtx, 0), 1)) == CONST_INT)
4243                 {
4244                   offset_rtx = copy_all_rtx (offset_rtx);
4245                   XEXP (XEXP (offset_rtx, 0), 1) =
4246                     gen_rtx (CONST_INT, 0, INTVAL (XEXP (XEXP (offset_rtx, 0), 1)) + offset_adjust);
4247                   if (!CONSTANT_P (offset_rtx))
4248                     {
4249                       obfree (storage);
4250                       return;
4251                     }
4252                 }
4253             }
4254           else if (GET_CODE (offset_rtx) == SYMBOL_REF)
4255             {
4256               offset_rtx =
4257                 gen_rtx (CONST, GET_MODE (offset_rtx),
4258                          gen_rtx (PLUS, GET_MODE (offset_rtx),
4259                                   offset_rtx,
4260                                   gen_rtx (CONST_INT, 0, offset_adjust)));
4261               if (!CONSTANT_P (offset_rtx))
4262                 {
4263                   obfree (storage);
4264                   return;
4265                 }
4266             }
4267           else if (GET_CODE (offset_rtx) == CONST_INT)
4268             {
4269               offset_rtx = gen_rtx (CONST_INT, 0, INTVAL (offset_rtx) + offset_adjust);
4270             }
4271           else
4272             {
4273               obfree (storage);
4274               return;
4275             }
4276         }
4277       else
4278         {
4279           offset_rtx = gen_rtx (CONST_INT, 0, offset_adjust);
4280         }
4281       if (index_rtx)
4282         {
4283           if (base_rtx)
4284             {
4285               if (scale != 1)
4286                 {
4287                   if (GET_CODE (offset_rtx) == CONST_INT &&
4288                       INTVAL (offset_rtx) == 0)
4289                     {
4290                       ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx),
4291                              gen_rtx (MULT, GET_MODE (index_rtx), index_rtx,
4292                                       scale_rtx),
4293                                          base_rtx);
4294                     }
4295                   else
4296                     {
4297                       ret_rtx = gen_rtx (PLUS, GET_MODE (offset_rtx),
4298                                          gen_rtx (PLUS, GET_MODE (base_rtx),
4299                              gen_rtx (MULT, GET_MODE (index_rtx), index_rtx,
4300                                       scale_rtx),
4301                                                   base_rtx),
4302                                          offset_rtx);
4303                     }
4304                 }
4305               else
4306                 {
4307                   if (GET_CODE (offset_rtx) == CONST_INT &&
4308                       INTVAL (offset_rtx) == 0)
4309                     {
4310                       ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx), index_rtx, base_rtx);
4311                     }
4312                   else
4313                     {
4314                       ret_rtx = gen_rtx (PLUS, GET_MODE (offset_rtx),
4315                              gen_rtx (PLUS, GET_MODE (index_rtx), index_rtx,
4316                                       base_rtx),
4317                                          offset_rtx);
4318                     }
4319                 }
4320             }
4321           else
4322             {
4323               if (scale != 1)
4324                 {
4325                   if (GET_CODE (offset_rtx) == CONST_INT &&
4326                       INTVAL (offset_rtx) == 0)
4327                     {
4328                       ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx), index_rtx, scale_rtx);
4329                     }
4330                   else
4331                     {
4332                       ret_rtx =
4333                         gen_rtx (PLUS, GET_MODE (offset_rtx),
4334                              gen_rtx (MULT, GET_MODE (index_rtx), index_rtx,
4335                                       scale_rtx),
4336                                  offset_rtx);
4337                     }
4338                 }
4339               else
4340                 {
4341                   if (GET_CODE (offset_rtx) == CONST_INT &&
4342                       INTVAL (offset_rtx) == 0)
4343                     {
4344                       ret_rtx = index_rtx;
4345                     }
4346                   else
4347                     {
4348                       ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx), index_rtx, offset_rtx);
4349                     }
4350                 }
4351             }
4352         }
4353       else
4354         {
4355           if (base_rtx)
4356             {
4357               if (GET_CODE (offset_rtx) == CONST_INT &&
4358                   INTVAL (offset_rtx) == 0)
4359                 {
4360                   ret_rtx = base_rtx;
4361                 }
4362               else
4363                 {
4364                   ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx, offset_rtx);
4365                 }
4366             }
4367           else if (was_only_offset)
4368             {
4369               ret_rtx = offset_rtx;
4370             }
4371           else
4372             {
4373               obfree (storage);
4374               return;
4375             }
4376         }
4377       XEXP (mem_rtx, 0) = ret_rtx;
4378       RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
4379       return;
4380     }
4381   else
4382     {
4383       obfree (storage);
4384       return;
4385     }
4386 }
4387 #endif /* NOTYET */
4388
4389 \f
4390 /* return 1 if the first insn to set cc before insn also sets the register
4391    reg_rtx - otherwise return 0 */
4392 int
4393 last_to_set_cc (reg_rtx, insn)
4394      rtx reg_rtx, insn;
4395 {
4396   rtx prev_insn = PREV_INSN (insn);
4397
4398   while (prev_insn)
4399     {
4400       if (GET_CODE (prev_insn) == NOTE)
4401         ;
4402
4403       else if (GET_CODE (prev_insn) == INSN)
4404         {
4405           if (GET_CODE (PATTERN (prev_insn)) != SET)
4406             return (0);
4407
4408           if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx))
4409             {
4410               if (sets_condition_code (SET_SRC (PATTERN (prev_insn))))
4411                 return (1);
4412
4413               return (0);
4414             }
4415
4416           else if (!doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn))))
4417             return (0);
4418         }
4419
4420       else
4421         return (0);
4422
4423       prev_insn = PREV_INSN (prev_insn);
4424     }
4425
4426   return (0);
4427 }
4428
4429 \f
4430 int
4431 doesnt_set_condition_code (pat)
4432      rtx pat;
4433 {
4434   switch (GET_CODE (pat))
4435     {
4436     case MEM:
4437     case REG:
4438       return (1);
4439
4440     default:
4441       return (0);
4442
4443     }
4444 }
4445
4446 \f
4447 int
4448 sets_condition_code (pat)
4449      rtx pat;
4450 {
4451   switch (GET_CODE (pat))
4452     {
4453     case PLUS:
4454     case MINUS:
4455     case AND:
4456     case IOR:
4457     case XOR:
4458     case NOT:
4459     case NEG:
4460     case MULT:
4461     case DIV:
4462     case MOD:
4463     case UDIV:
4464     case UMOD:
4465       return (1);
4466
4467     default:
4468       return (0);
4469
4470     }
4471 }
4472
4473 \f
4474 int
4475 str_immediate_operand (op, mode)
4476      register rtx op;
4477      enum machine_mode mode;
4478 {
4479   if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
4480     {
4481       return (1);
4482     }
4483   return (0);
4484 }
4485
4486 \f
4487 int
4488 is_fp_insn (insn)
4489      rtx insn;
4490 {
4491   if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
4492       && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
4493           || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
4494           || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode))
4495     {
4496       return (1);
4497     }
4498
4499   return (0);
4500 }
4501
4502 /*
4503   Return 1 if the mode of the SET_DEST of insn is floating point
4504   and it is not an fld or a move from memory to memory.
4505   Otherwise return 0 */
4506 int
4507 is_fp_dest (insn)
4508      rtx insn;
4509 {
4510   if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
4511       && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
4512           || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
4513           || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
4514       && GET_CODE (SET_DEST (PATTERN (insn))) == REG
4515       && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG
4516       && GET_CODE (SET_SRC (insn)) != MEM)
4517     {
4518       return (1);
4519     }
4520
4521   return (0);
4522 }
4523
4524 /*
4525   Return 1 if the mode of the SET_DEST floating point and is memory
4526   and the source is a register.  
4527 */
4528 int
4529 is_fp_store (insn)
4530      rtx insn;
4531 {
4532   if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
4533       && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
4534           || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
4535           || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
4536       && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
4537       && GET_CODE (SET_SRC (PATTERN (insn))) == REG)
4538     {
4539       return (1);
4540     }
4541
4542   return (0);
4543 }
4544
4545 \f
4546 /*
4547   Return 1 if dep_insn sets a register which insn uses as a base
4548   or index to reference memory.
4549   otherwise return 0 */
4550
4551 int
4552 agi_dependent (insn, dep_insn)
4553      rtx insn, dep_insn;
4554 {
4555   if (GET_CODE (dep_insn) == INSN
4556       && GET_CODE (PATTERN (dep_insn)) == SET
4557       && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG)
4558     {
4559       return (reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn));
4560     }
4561
4562   if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET
4563       && GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM
4564       && push_operand (SET_DEST (PATTERN (dep_insn)),
4565                        GET_MODE (SET_DEST (PATTERN (dep_insn)))))
4566     {
4567       return (reg_mentioned_in_mem (stack_pointer_rtx, insn));
4568     }
4569   
4570   return (0);
4571 }
4572
4573 \f
4574 /*
4575   Return 1 if reg is used in rtl as a base or index for a memory ref
4576   otherwise return 0. */
4577
4578 int
4579 reg_mentioned_in_mem (reg, rtl)
4580      rtx reg, rtl;
4581 {
4582   register char *fmt;
4583   register int i;
4584   register enum rtx_code code;
4585
4586   if (rtl == NULL)
4587     return (0);
4588
4589   code = GET_CODE (rtl);
4590
4591   switch (code)
4592     {
4593     case HIGH:
4594     case CONST_INT:
4595     case CONST:
4596     case CONST_DOUBLE:
4597     case SYMBOL_REF:
4598     case LABEL_REF:
4599     case PC:
4600     case CC0:
4601     case SUBREG:
4602       return (0);
4603
4604
4605     }
4606
4607   if (code == MEM && reg_mentioned_p (reg, rtl))
4608     return (1);
4609
4610   fmt = GET_RTX_FORMAT (code);
4611   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
4612     {
4613       if (fmt[i] == 'E')
4614         {
4615           register int j;
4616           for (j = XVECLEN (rtl, i) - 1; j >= 0; j--)
4617             {
4618               if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j)))
4619                 return 1;
4620             }
4621         }
4622
4623       else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i)))
4624         return 1;
4625     }
4626
4627   return (0);
4628 }
4629 \f
4630 /* Output the approprate insns for doing strlen if not just doing repnz; scasb
4631
4632    operands[0] = result, initialized with the startaddress
4633    operands[1] = alignment of the address.
4634    operands[2] = scratch register, initialized with the startaddress when
4635                  not aligned, otherwise undefined
4636
4637    This is just the body. It needs the initialisations mentioned above and
4638    some address computing at the end.  These things are done in i386.md.  */
4639
4640 char *
4641 output_strlen_unroll (operands)
4642      rtx operands[];
4643 {
4644   rtx xops[18];
4645
4646   xops[0] = operands[0];                /* Result */
4647   /*        operands[1];                 * Alignment */
4648   xops[1] = operands[2];                /* Scratch */
4649   xops[2] = GEN_INT (0);
4650   xops[3] = GEN_INT (2);
4651   xops[4] = GEN_INT (3);
4652   xops[5] = GEN_INT (4);
4653   /* xops[6] = gen_label_rtx ();         * label when aligned to 3-byte */
4654   /* xops[7] = gen_label_rtx ();         * label when aligned to 2-byte */
4655   xops[8] = gen_label_rtx ();           /* label of main loop */
4656   if(TARGET_USE_Q_REG && QI_REG_P (xops[1]))
4657     xops[9] = gen_label_rtx ();         /* pentium optimisation */
4658   xops[10] = gen_label_rtx ();          /* end label 2 */
4659   xops[11] = gen_label_rtx ();          /* end label 1 */
4660   xops[12] = gen_label_rtx ();          /* end label */
4661   /* xops[13]                            * Temporary used */
4662   xops[14] = GEN_INT (0xff);
4663   xops[15] = GEN_INT (0xff00);
4664   xops[16] = GEN_INT (0xff0000);
4665   xops[17] = GEN_INT (0xff000000);
4666
4667     /* Loop to check 1..3 bytes for null to get an aligned pointer */
4668
4669     /* is there a known alignment and is it less then 4 */
4670   if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
4671     {
4672         /* is there a known alignment and is it not 2 */
4673       if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
4674         {
4675           xops[6] = gen_label_rtx ();   /* label when aligned to 3-byte */
4676           xops[7] = gen_label_rtx ();   /* label when aligned to 2-byte */
4677
4678             /* leave just the 3 lower bits */
4679             /* if this is a q-register, then the high part is used later */
4680             /* therefore user andl rather than andb */
4681           output_asm_insn (AS2 (and%L1,%4,%1), xops);
4682             /* is aligned to 4-byte adress when zero */
4683           output_asm_insn (AS1 (je,%l8), xops);
4684             /* side-effect even Parity when %eax == 3 */
4685           output_asm_insn (AS1 (jp,%6), xops);
4686
4687             /* is it aligned to 2 bytes ? */
4688           if (QI_REG_P (xops[1]))
4689             output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
4690           else
4691             output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
4692           output_asm_insn (AS1 (je,%7), xops);
4693         }
4694       else
4695         {
4696             /* since the alignment is 2, we have to check 2 or 0 bytes */
4697
4698             /* check if is aligned to 4 - byte */
4699           output_asm_insn (AS2 (and%L1,%3,%1), xops);
4700             /* is aligned to 4-byte adress when zero */
4701           output_asm_insn (AS1 (je,%l8), xops);
4702         }
4703
4704       xops[13] = gen_rtx (MEM, QImode, xops[0]);
4705         /* now, compare the bytes */
4706         /* compare with the high part of a q-reg gives shorter code */
4707       if (QI_REG_P (xops[1]))
4708         {
4709             /* compare the first n unaligned byte on a byte per byte basis */
4710           output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
4711             /* when zero we reached the end */
4712           output_asm_insn (AS1 (je,%l12), xops);
4713             /* increment the address */
4714           output_asm_insn (AS1 (inc%L0,%0), xops);
4715
4716             /* not needed with an alignment of 2 */
4717           if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
4718             {
4719               ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[7]));
4720               output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
4721               output_asm_insn (AS1 (je,%l12), xops);
4722               output_asm_insn (AS1 (inc%L0,%0), xops);
4723
4724               ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[6]));
4725             }
4726           output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
4727         }
4728       else
4729         {
4730           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
4731           output_asm_insn (AS1 (je,%l12), xops);
4732           output_asm_insn (AS1 (inc%L0,%0), xops);
4733
4734           ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[7]));
4735           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
4736           output_asm_insn (AS1 (je,%l12), xops);
4737           output_asm_insn (AS1 (inc%L0,%0), xops);
4738
4739           ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[6]));
4740           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
4741         }
4742       output_asm_insn (AS1 (je,%l12), xops);
4743       output_asm_insn (AS1 (inc%L0,%0), xops);
4744     }
4745
4746     /* Generate loop to check 4 bytes at a time */
4747     /* IMHO it is not a good idea to align this loop.  It gives only */
4748     /* huge programs, but does not help to speed up */
4749   /* ASM_OUTPUT_LOOP_ALIGN (asm_out_file); */
4750   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
4751
4752   xops[13] = gen_rtx (MEM, SImode, xops[0]);
4753   output_asm_insn (AS2 (mov%L1,%13,%1), xops);
4754
4755   if (QI_REG_P (xops[1]))
4756     {
4757       /* On i586 it is faster to combine the hi- and lo- part as
4758          a kind of lookahead.  If anding both yields zero, then one
4759          of both *could* be zero, otherwise none of both is zero;
4760          this saves one instruction, on i486 this is slower
4761          tested with P-90, i486DX2-66, AMD486DX2-66  */
4762       if(TARGET_PENTIUM)
4763         {
4764           output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
4765           output_asm_insn (AS1 (jne,%l9), xops);
4766         }
4767
4768         /* check first byte */
4769       output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
4770       output_asm_insn (AS1 (je,%l12), xops);
4771
4772         /* check second byte */
4773       output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
4774       output_asm_insn (AS1 (je,%l11), xops);
4775
4776       if(TARGET_PENTIUM)
4777           ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[9]));
4778     }
4779   else
4780     {
4781         /* check first byte */
4782       output_asm_insn (AS2 (test%L1,%14,%1), xops);
4783       output_asm_insn (AS1 (je,%l12), xops);
4784
4785         /* check second byte */
4786       output_asm_insn (AS2 (test%L1,%15,%1), xops);
4787       output_asm_insn (AS1 (je,%l11), xops);
4788     }
4789
4790     /* check third byte */
4791   output_asm_insn (AS2 (test%L1,%16,%1), xops);
4792   output_asm_insn (AS1 (je,%l10), xops);
4793   
4794     /* check fourth byte and increment address */
4795   output_asm_insn (AS2 (add%L0,%5,%0), xops);
4796   output_asm_insn (AS2 (test%L1,%17,%1), xops);
4797   output_asm_insn (AS1 (jne,%l8), xops);
4798
4799     /* now generate fixups when the compare stops within a 4-byte word */
4800   output_asm_insn (AS2 (sub%L0,%4,%0), xops);
4801
4802   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
4803   output_asm_insn (AS1 (inc%L0,%0), xops);
4804
4805   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
4806   output_asm_insn (AS1 (inc%L0,%0), xops);
4807
4808   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
4809
4810   RET;
4811 }