OSDN Git Service

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