OSDN Git Service

Change FSF address.
[pf3gnuchains/gcc-fork.git] / gcc / config / ns32k / ns32k.c
1 /* Subroutines for assembler code output on the NS32000.
2    Copyright (C) 1988, 1994, 1995 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 /* Some output-actions in ns32k.md need these.  */
22 #include <stdio.h>
23 #include "config.h"
24 #include "rtl.h"
25 #include "regs.h"
26 #include "hard-reg-set.h"
27 #include "real.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-flags.h"
31 #include "output.h"
32 #include "insn-attr.h"
33
34 #ifdef OSF_OS
35 int ns32k_num_files = 0;
36 #endif
37
38 void
39 trace (s, s1, s2)
40      char *s, *s1, *s2;
41 {
42   fprintf (stderr, s, s1, s2);
43 }
44
45 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
46
47 int
48 hard_regno_mode_ok (regno, mode)
49      int regno;
50      enum machine_mode mode;
51 {
52   switch (mode)
53     {
54     case QImode:
55     case HImode:
56     case PSImode:
57     case SImode:
58     case PDImode:
59     case VOIDmode:
60     case BLKmode:
61       if (regno < 8 || regno == 16 || regno == 17)
62         return 1;
63       else
64         return 0;
65
66     case DImode:
67       if (regno < 8 && (regno & 1) == 0)
68         return 1;
69       else
70         return 0;
71
72     case SFmode:
73     case SCmode:
74       if (TARGET_32081)
75         {
76           if (regno < 16)
77             return 1;
78           else
79             return 0;
80         }
81       else
82         {
83           if (regno < 8)
84             return 1;
85           else 
86             return 0;
87         }
88
89     case DFmode:
90     case DCmode:
91       if ((regno & 1) == 0)
92         {       
93           if (TARGET_32081)
94             {
95               if (regno < 16)
96                 return 1;
97               else
98                 return 0;
99             }
100           else
101             {
102               if (regno < 8)
103                 return 1;
104               else
105                 return 0;
106             }
107         }
108       else
109         return 0;
110     }
111
112   /* Used to abort here, but simply saying "no" handles TImode
113      much better.  */
114   return 0;
115 }
116
117 /* ADDRESS_COST calls this.  This function is not optimal
118    for the 32032 & 32332, but it probably is better than
119    the default. */
120
121 int
122 calc_address_cost (operand)
123      rtx operand;
124 {
125   int i;
126   int cost = 0;
127   
128   if (GET_CODE (operand) == MEM)
129     cost += 3;
130   if (GET_CODE (operand) == MULT)
131     cost += 2;
132 #if 0
133   if (GET_CODE (operand) == REG)
134     cost += 1;                  /* not really, but the documentation
135                                    says different amount of registers
136                                    shouldn't return the same costs */
137 #endif
138   switch (GET_CODE (operand))
139     {
140     case REG:
141     case CONST:
142     case CONST_INT:
143     case CONST_DOUBLE:
144     case SYMBOL_REF:
145     case LABEL_REF:
146     case POST_DEC:
147     case PRE_DEC:
148       break;
149     case MULT:
150     case MEM:
151     case PLUS:
152       for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
153         {
154           cost += calc_address_cost (XEXP (operand, i));
155         }
156     default:
157       break;
158     }
159   return cost;
160 }
161
162 /* Return the register class of a scratch register needed to copy IN into
163    or out of a register in CLASS in MODE.  If it can be done directly,
164    NO_REGS is returned.  */
165
166 enum reg_class
167 secondary_reload_class (class, mode, in)
168      enum reg_class class;
169      enum machine_mode mode;
170      rtx in;
171 {
172   int regno = true_regnum (in);
173
174   if (regno >= FIRST_PSEUDO_REGISTER)
175     regno = -1;
176
177   /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
178      into anything.  */
179   if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
180     return NO_REGS;
181
182   /* Constants, memory, and FP registers can go into FP registers.  */
183   if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
184     return NO_REGS;
185
186 #if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
187          so it's cleaner to use PREFERRED_RELOAD_CLASS
188          to make the right things happen.  */
189   if (regno >= 16 && class == GEN_AND_MEM_REGS)
190     return NO_REGS;
191 #endif
192
193   /* Otherwise, we need GENERAL_REGS. */
194   return GENERAL_REGS;
195 }
196 /* Generate the rtx that comes from an address expression in the md file */
197 /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
198    scale must be converted from an exponent (from ASHIFT) to a
199    multiplier (for MULT). */
200 rtx
201 gen_indexed_expr (base, index, scale)
202      rtx base, index, scale;
203 {
204   rtx addr;
205
206   /* This generates an invalid addressing mode, if BASE is
207      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
208   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
209     base = gen_rtx (MEM, SImode, base);
210   addr = gen_rtx (MULT, SImode, index,
211                   gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
212   addr = gen_rtx (PLUS, SImode, base, addr);
213   return addr;
214 }
215
216 /* Return 1 if OP is a valid operand of mode MODE.  This
217    predicate rejects operands which do not have a mode
218    (such as CONST_INT which are VOIDmode).  */
219 int
220 reg_or_mem_operand (op, mode)
221      register rtx op;
222      enum machine_mode mode;
223 {
224   return (GET_MODE (op) == mode
225           && (GET_CODE (op) == REG
226               || GET_CODE (op) == SUBREG
227               || GET_CODE (op) == MEM));
228 }
229 \f
230 /* Return the best assembler insn template
231    for moving operands[1] into operands[0] as a fullword.  */
232
233 static char *
234 singlemove_string (operands)
235      rtx *operands;
236 {
237   if (GET_CODE (operands[1]) == CONST_INT
238       && INTVAL (operands[1]) <= 7
239       && INTVAL (operands[1]) >= -8)
240     return "movqd %1,%0";
241   return "movd %1,%0";
242 }
243
244 char *
245 output_move_double (operands)
246      rtx *operands;
247 {
248   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
249   rtx latehalf[2];
250
251   /* First classify both operands.  */
252
253   if (REG_P (operands[0]))
254     optype0 = REGOP;
255   else if (offsettable_memref_p (operands[0]))
256     optype0 = OFFSOP;
257   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
258     optype0 = PUSHOP;
259   else
260     optype0 = RNDOP;
261
262   if (REG_P (operands[1]))
263     optype1 = REGOP;
264   else if (CONSTANT_P (operands[1])
265            || GET_CODE (operands[1]) == CONST_DOUBLE)
266     optype1 = CNSTOP;
267   else if (offsettable_memref_p (operands[1]))
268     optype1 = OFFSOP;
269   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
270     optype1 = PUSHOP;
271   else
272     optype1 = RNDOP;
273
274   /* Check for the cases that the operand constraints are not
275      supposed to allow to happen.  Abort if we get one,
276      because generating code for these cases is painful.  */
277
278   if (optype0 == RNDOP || optype1 == RNDOP)
279     abort ();
280
281   /* Ok, we can do one word at a time.
282      Normally we do the low-numbered word first,
283      but if either operand is autodecrementing then we
284      do the high-numbered word first.
285
286      In either case, set up in LATEHALF the operands to use
287      for the high-numbered word and in some cases alter the
288      operands in OPERANDS to be suitable for the low-numbered word.  */
289
290   if (optype0 == REGOP)
291     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
292   else if (optype0 == OFFSOP)
293     latehalf[0] = adj_offsettable_operand (operands[0], 4);
294   else
295     latehalf[0] = operands[0];
296
297   if (optype1 == REGOP)
298     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
299   else if (optype1 == OFFSOP)
300     latehalf[1] = adj_offsettable_operand (operands[1], 4);
301   else if (optype1 == CNSTOP)
302     split_double (operands[1], &operands[1], &latehalf[1]);
303   else
304     latehalf[1] = operands[1];
305
306   /* If insn is effectively movd N(sp),tos then we will do the
307      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
308      for the low word as well, to compensate for the first decrement of sp.
309      Given this, it doesn't matter which half we do "first".  */
310   if (optype0 == PUSHOP
311       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
312       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
313     operands[1] = latehalf[1];
314
315   /* If one or both operands autodecrementing,
316      do the two words, high-numbered first.  */
317   else if (optype0 == PUSHOP || optype1 == PUSHOP)
318     {
319       output_asm_insn (singlemove_string (latehalf), latehalf);
320       return singlemove_string (operands);
321     }
322
323   /* If the first move would clobber the source of the second one,
324      do them in the other order.  */
325
326   /* Overlapping registers.  */
327   if (optype0 == REGOP && optype1 == REGOP
328       && REGNO (operands[0]) == REGNO (latehalf[1]))
329     {
330       /* Do that word.  */
331       output_asm_insn (singlemove_string (latehalf), latehalf);
332       /* Do low-numbered word.  */
333       return singlemove_string (operands);
334     }
335   /* Loading into a register which overlaps a register used in the address.  */
336   else if (optype0 == REGOP && optype1 != REGOP
337            && reg_overlap_mentioned_p (operands[0], operands[1]))
338     {
339       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
340           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
341         {
342           /* If both halves of dest are used in the src memory address,
343              load the destination address into the low reg (operands[0]).
344              Then it works to load latehalf first.  */
345           rtx xops[2];
346           xops[0] = XEXP (operands[1], 0);
347           xops[1] = operands[0];
348           output_asm_insn ("addr %a0,%1", xops);
349           operands[1] = gen_rtx (MEM, DImode, operands[0]);
350           latehalf[1] = adj_offsettable_operand (operands[1], 4);
351           /* The first half has the overlap, Do the late half first.  */
352           output_asm_insn (singlemove_string (latehalf), latehalf);
353           /* Then clobber.  */
354           return singlemove_string (operands);
355         }
356       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
357         {
358           /* The first half has the overlap, Do the late half first.  */
359           output_asm_insn (singlemove_string (latehalf), latehalf);
360           /* Then clobber.  */
361           return singlemove_string (operands);
362         }
363     }
364
365   /* Normal case.  Do the two words, low-numbered first.  */
366
367   output_asm_insn (singlemove_string (operands), operands);
368
369   operands[0] = latehalf[0];
370   operands[1] = latehalf[1];
371   return singlemove_string (operands);
372 }
373
374 int
375 check_reg (oper, reg)
376      rtx oper;
377      int reg;
378 {
379   register int i;
380
381   if (oper == 0)
382     return 0;
383   switch (GET_CODE(oper))
384     {
385     case REG:
386       return (REGNO(oper) == reg) ? 1 : 0;
387     case MEM:
388       return check_reg(XEXP(oper, 0), reg);
389     case PLUS:
390     case MULT:
391       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
392     }
393   return 0;
394 }
395
396 /* Returns 1 if OP contains a global symbol reference */
397
398 int
399 global_symbolic_reference_mentioned_p (op, f)
400      rtx op;
401      int f;
402 {
403   register char *fmt;
404   register int i;
405
406   if (GET_CODE (op) == SYMBOL_REF)
407     {
408       if (! SYMBOL_REF_FLAG (op))
409         return 1;
410       else
411         return 0;
412     }
413   else if (f && GET_CODE (op) != CONST)
414     return 0;
415
416   fmt = GET_RTX_FORMAT (GET_CODE (op));
417   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
418     {
419       if (fmt[i] == 'E')
420         {
421           register int j;
422
423           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
424             if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
425               return 1;
426         }
427       else if (fmt[i] == 'e' 
428                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
429         return 1;
430     }
431
432   return 0;
433 }
434
435 \f
436 /* PRINT_OPERAND is defined to call this function,
437    which is easier to debug than putting all the code in
438    a macro definition in ns32k.h.  */
439
440 void
441 print_operand (file, x, code)
442      FILE *file;
443      rtx x;
444      char code;
445 {
446   if (code == '$')
447     PUT_IMMEDIATE_PREFIX (file);
448   else if (code == '?')
449     PUT_EXTERNAL_PREFIX (file);
450   else if (GET_CODE (x) == REG)
451     fprintf (file, "%s", reg_names[REGNO (x)]);
452   else if (GET_CODE (x) == MEM)
453     {
454       rtx tmp = XEXP (x, 0);
455       output_address (XEXP (x, 0));
456     }
457   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
458     {
459       if (GET_MODE (x) == DFmode)
460         { 
461           union { double d; int i[2]; } u;
462           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
463           PUT_IMMEDIATE_PREFIX(file);
464 #ifdef SEQUENT_ASM
465           /* Sequent likes it's floating point constants as integers */
466           fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
467 #else
468 #ifdef ENCORE_ASM
469           fprintf (file, "0f%.20e", u.d); 
470 #else
471           fprintf (file, "0d%.20e", u.d); 
472 #endif
473 #endif
474         }
475       else
476         { 
477           union { double d; int i[2]; } u;
478           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
479           PUT_IMMEDIATE_PREFIX (file);
480 #ifdef SEQUENT_ASM
481           /* We have no way of winning if we can't get the bits
482              for a sequent floating point number.  */
483 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
484           abort ();
485 #endif
486           {
487             union { float f; long l; } uu;
488             uu.f = u.d;
489             fprintf (file, "0Fx%08x", uu.l);
490           }
491 #else
492           fprintf (file, "0f%.20e", u.d); 
493 #endif
494         }
495     }
496   else
497     {
498 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
499       if (GET_CODE (x) == CONST_INT)
500 #endif
501         PUT_IMMEDIATE_PREFIX (file);
502       output_addr_const (file, x);
503     }
504 }
505 \f
506 /* PRINT_OPERAND_ADDRESS is defined to call this function,
507    which is easier to debug than putting all the code in
508    a macro definition in ns32k.h .  */
509
510 /* Completely rewritten to get this to work with Gas for PC532 Mach.
511    This function didn't work and I just wasn't able (nor very willing) to
512    figure out how it worked.
513    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
514
515 print_operand_address (file, addr)
516      register FILE *file;
517      register rtx addr;
518 {
519   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
520   rtx offset, base, indexexp, tmp;
521   int scale;
522   extern int flag_pic;
523
524   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
525     {
526       fprintf (file, "tos");
527       return;
528     }
529
530   offset = NULL;
531   base = NULL;
532   indexexp = NULL;
533   while (addr != NULL)
534     {
535       if (GET_CODE (addr) == PLUS)
536         {
537           if (GET_CODE (XEXP (addr, 0)) == PLUS)
538             {
539               tmp = XEXP (addr, 1);
540               addr = XEXP (addr, 0);
541             }
542           else
543             {
544               tmp = XEXP (addr,0);
545               addr = XEXP (addr,1);
546             }
547         }
548       else
549         {
550           tmp = addr;
551           addr = NULL;
552         }
553       switch (GET_CODE (tmp))
554         {
555         case PLUS:
556           abort ();
557         case MEM:
558           if (base)
559             {
560               indexexp = base;
561               base = tmp;
562             }
563           else
564             base = tmp;
565           break;
566         case REG:
567           if (REGNO (tmp) < 8)
568             if (base)
569               {
570                 indexexp = tmp;
571               }
572             else
573               base = tmp;
574           else
575             if (base)
576               {
577                 indexexp = base;
578                 base = tmp;
579               }
580             else
581               base = tmp;
582           break;
583         case MULT:
584           indexexp = tmp;
585           break;
586         case SYMBOL_REF:
587           if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
588               && ! SYMBOL_REF_FLAG (tmp))
589             {
590               if (base)
591                 {
592                   if (indexexp)
593                     abort ();
594                   indexexp = base;
595                 }
596               base = tmp;
597               break;
598             }
599         case CONST:
600           if (flag_pic && GET_CODE (tmp) == CONST)
601             {
602               rtx sym, off, tmp1;
603               tmp1 = XEXP (tmp,0);
604               if (GET_CODE (tmp1)  != PLUS)
605                 abort ();
606
607               sym = XEXP (tmp1,0);
608               if (GET_CODE (sym) != SYMBOL_REF)
609                 {
610                   off = sym;
611                   sym = XEXP (tmp1,1);
612                 }
613               else
614                 off = XEXP (tmp1,1);
615               if (GET_CODE (sym) == SYMBOL_REF)
616                 {
617                   if (GET_CODE (off) != CONST_INT)
618                     abort ();
619
620                   if (CONSTANT_POOL_ADDRESS_P (sym)
621                       || SYMBOL_REF_FLAG (sym))
622                     {
623                       SYMBOL_REF_FLAG (tmp) = 1;
624                     }
625                   else
626                     {
627                       if (base)
628                         {
629                           if (indexexp)
630                             abort ();
631
632                           indexexp = base;
633                         }
634
635                       if (offset != 0)
636                         abort ();
637
638                       base = sym;
639                       offset = off;
640                       break;
641                     }
642                 }
643             }
644         case CONST_INT:
645         case LABEL_REF:
646           if (offset)
647             offset = gen_rtx (PLUS, SImode, tmp, offset);
648           else
649             offset = tmp;
650           break;
651         default:
652           abort ();
653         }
654     }
655   if (! offset)
656     offset = const0_rtx;
657
658   if (base
659 #ifndef INDEX_RATHER_THAN_BASE
660       && (flag_pic || TARGET_HIMEM)
661       && GET_CODE (base) != SYMBOL_REF 
662       && GET_CODE (offset) != CONST_INT
663 #else
664   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
665 #endif
666       && !indexexp && GET_CODE (base) == REG
667       && REG_OK_FOR_INDEX_P (base))
668     {
669       indexexp = base;
670       base = NULL;
671     }
672
673   /* now, offset, base and indexexp are set */
674 #ifndef BASE_REG_NEEDED
675   if (! base)
676     {
677 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
678       if (GET_CODE (offset) == CONST_INT)
679 #endif
680         PUT_ABSOLUTE_PREFIX (file);
681     }
682 #endif
683
684   output_addr_const (file, offset);
685   if (base) /* base can be (REG ...) or (MEM ...) */
686     switch (GET_CODE (base))
687       {
688         /* now we must output base.  Possible alternatives are:
689            (rN)       (REG ...)
690            (sp)       (REG ...)
691            (fp)       (REG ...)
692            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
693            (disp(fp)) (MEM ...)       just before possible [rX:y]
694            (disp(sp)) (MEM ...)
695            (disp(sb)) (MEM ...)
696            */
697       case REG:
698         fprintf (file, "(%s)", reg_names[REGNO (base)]);
699         break;
700       case SYMBOL_REF:
701         if (! flag_pic)
702           abort ();
703
704         fprintf (file, "(");
705         output_addr_const (file, base);
706         fprintf (file, "(sb))");
707         break;
708       case MEM:
709         addr = XEXP(base,0);
710         base = NULL;
711         offset = NULL;
712         while (addr != NULL)
713           {
714             if (GET_CODE (addr) == PLUS)
715               {
716                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
717                   {
718                     tmp = XEXP (addr, 1);
719                     addr = XEXP (addr, 0);
720                   }
721                 else
722                   {
723                     tmp = XEXP (addr, 0);
724                     addr = XEXP (addr, 1);
725                   }
726               }
727             else
728               {
729                 tmp = addr;
730                 addr = NULL;
731               }
732             switch (GET_CODE (tmp))
733               {
734               case REG:
735                 base = tmp;
736                 break;
737               case CONST:
738               case CONST_INT:
739               case SYMBOL_REF:
740               case LABEL_REF:
741                 if (offset)
742                   offset = gen_rtx (PLUS, SImode, tmp, offset);
743                 else
744                   offset = tmp;
745                 break;
746               default:
747                 abort ();
748               }
749           }
750         if (! offset)
751           offset = const0_rtx;
752         fprintf (file, "(");
753         output_addr_const (file, offset);
754         if (base)
755           fprintf (file, "(%s)", reg_names[REGNO (base)]);
756         else if (TARGET_SB)
757           fprintf (file, "(sb)");
758         else
759           abort ();
760         fprintf (file, ")");
761         break;
762       default:
763         abort ();
764       }
765 #ifdef PC_RELATIVE
766   else if (GET_CODE (offset) != CONST_INT)
767     fprintf (file, "(pc)");
768 #ifdef BASE_REG_NEEDED
769   else if (TARGET_SB)
770     fprintf (file, "(sb)");
771   else
772     abort ();
773 #endif
774 #endif /* PC_RELATIVE */
775
776   /* now print index if we have one */
777   if (indexexp)
778     {
779       if (GET_CODE (indexexp) == MULT)
780         {
781           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
782           indexexp = XEXP (indexexp, 0);
783         }
784       else
785         scale = 0;
786       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
787         abort ();
788
789 #ifdef UTEK_ASM
790       fprintf (file, "[%c`%s]",
791                scales[scale],
792                reg_names[REGNO (indexexp)]);
793 #else
794       fprintf (file, "[%s:%c]",
795                reg_names[REGNO (indexexp)],
796                scales[scale]);
797 #endif
798     }
799 }
800 \f
801 /* National 32032 shifting is so bad that we can get
802    better performance in many common cases by using other
803    techniques.  */
804 char *
805 output_shift_insn (operands)
806      rtx *operands;
807 {
808   if (GET_CODE (operands[2]) == CONST_INT
809       && INTVAL (operands[2]) > 0
810       && INTVAL (operands[2]) <= 3)
811     if (GET_CODE (operands[0]) == REG)
812       {
813         if (GET_CODE (operands[1]) == REG)
814           {
815             if (REGNO (operands[0]) == REGNO (operands[1]))
816               {
817                 if (operands[2] == const1_rtx)
818                   return "addd %0,%0";
819                 else if (INTVAL (operands[2]) == 2)
820                   return "addd %0,%0\n\taddd %0,%0";
821               }
822             if (operands[2] == const1_rtx)
823               return "movd %1,%0\n\taddd %0,%0";
824             
825             operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
826             return "addr %a1,%0";
827           }
828         if (operands[2] == const1_rtx)
829           return "movd %1,%0\n\taddd %0,%0";
830       }
831     else if (GET_CODE (operands[1]) == REG)
832       {
833         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
834         return "addr %a1,%0";
835       }
836     else if (INTVAL (operands[2]) == 1
837              && GET_CODE (operands[1]) == MEM
838              && rtx_equal_p (operands [0], operands[1]))
839       {
840         rtx temp = XEXP (operands[1], 0);
841         
842         if (GET_CODE (temp) == REG
843             || (GET_CODE (temp) == PLUS
844                 && GET_CODE (XEXP (temp, 0)) == REG
845                 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
846           return "addd %0,%0";
847       }
848     else return "ashd %2,%0";
849   return "ashd %2,%0";
850 }
851
852 char *
853 output_move_dconst (n, s)
854         int n;
855         char *s;
856 {
857   static char r[32];
858
859   if (n > -9 && n < 8)
860     strcpy (r, "movqd ");
861   else if (n > 0 && n < 256)
862     strcpy (r, "movzbd ");
863   else if (n > 0 && n < 65536)
864     strcpy (r, "movzwd ");
865   else if (n < 0 && n > -129)
866     strcpy (r, "movxbd ");
867   else if (n < 0 && n > -32769)
868     strcpy (r, "movxwd ");
869   else
870     strcpy (r, "movd ");
871   strcat (r, s);
872   return r;
873 }