OSDN Git Service

* 1750a.md, arm.c, clipper.c, clipper.md: Use GEN_INT consistently.
[pf3gnuchains/gcc-fork.git] / gcc / config / ns32k / ns32k.c
1 /* Subroutines for assembler code output on the NS32000.
2    Copyright (C) 1988, 1994, 1995, 1996, 1997 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 "config.h"
23 #include <stdio.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_INT (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 /* Split one or more DImode RTL references into pairs of SImode
231    references.  The RTL can be REG, offsettable MEM, integer constant, or
232    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
233    split and "num" is its length.  lo_half and hi_half are output arrays
234    that parallel "operands". */
235
236 void
237 split_di (operands, num, lo_half, hi_half)
238      rtx operands[];
239      int num;
240      rtx lo_half[], hi_half[];
241 {
242   while (num--)
243     {
244       if (GET_CODE (operands[num]) == REG)
245         {
246           lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
247           hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
248         }
249       else if (CONSTANT_P (operands[num]))
250         {
251           split_double (operands[num], &lo_half[num], &hi_half[num]);
252         }
253       else if (offsettable_memref_p (operands[num]))
254         {
255           lo_half[num] = operands[num];
256           hi_half[num] = adj_offsettable_operand (operands[num], 4);
257         }
258       else
259         abort();
260     }
261 }
262 \f
263 /* Return the best assembler insn template
264    for moving operands[1] into operands[0] as a fullword.  */
265
266 static char *
267 singlemove_string (operands)
268      rtx *operands;
269 {
270   if (GET_CODE (operands[1]) == CONST_INT
271       && INTVAL (operands[1]) <= 7
272       && INTVAL (operands[1]) >= -8)
273     return "movqd %1,%0";
274   return "movd %1,%0";
275 }
276
277 char *
278 output_move_double (operands)
279      rtx *operands;
280 {
281   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
282   rtx latehalf[2];
283
284   /* First classify both operands.  */
285
286   if (REG_P (operands[0]))
287     optype0 = REGOP;
288   else if (offsettable_memref_p (operands[0]))
289     optype0 = OFFSOP;
290   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
291     optype0 = PUSHOP;
292   else
293     optype0 = RNDOP;
294
295   if (REG_P (operands[1]))
296     optype1 = REGOP;
297   else if (CONSTANT_P (operands[1])
298            || GET_CODE (operands[1]) == CONST_DOUBLE)
299     optype1 = CNSTOP;
300   else if (offsettable_memref_p (operands[1]))
301     optype1 = OFFSOP;
302   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
303     optype1 = PUSHOP;
304   else
305     optype1 = RNDOP;
306
307   /* Check for the cases that the operand constraints are not
308      supposed to allow to happen.  Abort if we get one,
309      because generating code for these cases is painful.  */
310
311   if (optype0 == RNDOP || optype1 == RNDOP)
312     abort ();
313
314   /* Ok, we can do one word at a time.
315      Normally we do the low-numbered word first,
316      but if either operand is autodecrementing then we
317      do the high-numbered word first.
318
319      In either case, set up in LATEHALF the operands to use
320      for the high-numbered word and in some cases alter the
321      operands in OPERANDS to be suitable for the low-numbered word.  */
322
323   if (optype0 == REGOP)
324     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
325   else if (optype0 == OFFSOP)
326     latehalf[0] = adj_offsettable_operand (operands[0], 4);
327   else
328     latehalf[0] = operands[0];
329
330   if (optype1 == REGOP)
331     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
332   else if (optype1 == OFFSOP)
333     latehalf[1] = adj_offsettable_operand (operands[1], 4);
334   else if (optype1 == CNSTOP)
335     split_double (operands[1], &operands[1], &latehalf[1]);
336   else
337     latehalf[1] = operands[1];
338
339   /* If insn is effectively movd N(sp),tos then we will do the
340      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
341      for the low word as well, to compensate for the first decrement of sp.
342      Given this, it doesn't matter which half we do "first".  */
343   if (optype0 == PUSHOP
344       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
345       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
346     operands[1] = latehalf[1];
347
348   /* If one or both operands autodecrementing,
349      do the two words, high-numbered first.  */
350   else if (optype0 == PUSHOP || optype1 == PUSHOP)
351     {
352       output_asm_insn (singlemove_string (latehalf), latehalf);
353       return singlemove_string (operands);
354     }
355
356   /* If the first move would clobber the source of the second one,
357      do them in the other order.  */
358
359   /* Overlapping registers.  */
360   if (optype0 == REGOP && optype1 == REGOP
361       && REGNO (operands[0]) == REGNO (latehalf[1]))
362     {
363       /* Do that word.  */
364       output_asm_insn (singlemove_string (latehalf), latehalf);
365       /* Do low-numbered word.  */
366       return singlemove_string (operands);
367     }
368   /* Loading into a register which overlaps a register used in the address.  */
369   else if (optype0 == REGOP && optype1 != REGOP
370            && reg_overlap_mentioned_p (operands[0], operands[1]))
371     {
372       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
373           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
374         {
375           /* If both halves of dest are used in the src memory address,
376              load the destination address into the low reg (operands[0]).
377              Then it works to load latehalf first.  */
378           rtx xops[2];
379           xops[0] = XEXP (operands[1], 0);
380           xops[1] = operands[0];
381           output_asm_insn ("addr %a0,%1", xops);
382           operands[1] = gen_rtx (MEM, DImode, operands[0]);
383           latehalf[1] = adj_offsettable_operand (operands[1], 4);
384           /* The first half has the overlap, Do the late half first.  */
385           output_asm_insn (singlemove_string (latehalf), latehalf);
386           /* Then clobber.  */
387           return singlemove_string (operands);
388         }
389       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
390         {
391           /* The first half has the overlap, Do the late half first.  */
392           output_asm_insn (singlemove_string (latehalf), latehalf);
393           /* Then clobber.  */
394           return singlemove_string (operands);
395         }
396     }
397
398   /* Normal case.  Do the two words, low-numbered first.  */
399
400   output_asm_insn (singlemove_string (operands), operands);
401
402   operands[0] = latehalf[0];
403   operands[1] = latehalf[1];
404   return singlemove_string (operands);
405 }
406
407 int
408 check_reg (oper, reg)
409      rtx oper;
410      int reg;
411 {
412   register int i;
413
414   if (oper == 0)
415     return 0;
416   switch (GET_CODE(oper))
417     {
418     case REG:
419       return (REGNO(oper) == reg) ? 1 : 0;
420     case MEM:
421       return check_reg(XEXP(oper, 0), reg);
422     case PLUS:
423     case MULT:
424       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
425     }
426   return 0;
427 }
428
429 /* Returns 1 if OP contains a global symbol reference */
430
431 int
432 global_symbolic_reference_mentioned_p (op, f)
433      rtx op;
434      int f;
435 {
436   register char *fmt;
437   register int i;
438
439   if (GET_CODE (op) == SYMBOL_REF)
440     {
441       if (! SYMBOL_REF_FLAG (op))
442         return 1;
443       else
444         return 0;
445     }
446   else if (f && GET_CODE (op) != CONST)
447     return 0;
448
449   fmt = GET_RTX_FORMAT (GET_CODE (op));
450   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
451     {
452       if (fmt[i] == 'E')
453         {
454           register int j;
455
456           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
457             if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
458               return 1;
459         }
460       else if (fmt[i] == 'e' 
461                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
462         return 1;
463     }
464
465   return 0;
466 }
467
468 \f
469 /* PRINT_OPERAND is defined to call this function,
470    which is easier to debug than putting all the code in
471    a macro definition in ns32k.h.  */
472
473 void
474 print_operand (file, x, code)
475      FILE *file;
476      rtx x;
477      char code;
478 {
479   if (code == '$')
480     PUT_IMMEDIATE_PREFIX (file);
481   else if (code == '?')
482     PUT_EXTERNAL_PREFIX (file);
483   else if (GET_CODE (x) == REG)
484     fprintf (file, "%s", reg_names[REGNO (x)]);
485   else if (GET_CODE (x) == MEM)
486     {
487       rtx tmp = XEXP (x, 0);
488       output_address (XEXP (x, 0));
489     }
490   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
491     {
492       if (GET_MODE (x) == DFmode)
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           /* Sequent likes it's floating point constants as integers */
499           fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
500 #else
501 #ifdef ENCORE_ASM
502           fprintf (file, "0f%.20e", u.d); 
503 #else
504           fprintf (file, "0d%.20e", u.d); 
505 #endif
506 #endif
507         }
508       else
509         { 
510           union { double d; int i[2]; } u;
511           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
512           PUT_IMMEDIATE_PREFIX (file);
513 #ifdef SEQUENT_ASM
514           /* We have no way of winning if we can't get the bits
515              for a sequent floating point number.  */
516 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
517           abort ();
518 #endif
519           {
520             union { float f; long l; } uu;
521             uu.f = u.d;
522             fprintf (file, "0Fx%08x", uu.l);
523           }
524 #else
525           fprintf (file, "0f%.20e", u.d); 
526 #endif
527         }
528     }
529   else
530     {
531 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
532       if (GET_CODE (x) == CONST_INT)
533 #endif
534         PUT_IMMEDIATE_PREFIX (file);
535       output_addr_const (file, x);
536     }
537 }
538 \f
539 /* PRINT_OPERAND_ADDRESS is defined to call this function,
540    which is easier to debug than putting all the code in
541    a macro definition in ns32k.h .  */
542
543 /* Completely rewritten to get this to work with Gas for PC532 Mach.
544    This function didn't work and I just wasn't able (nor very willing) to
545    figure out how it worked.
546    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
547
548 print_operand_address (file, addr)
549      register FILE *file;
550      register rtx addr;
551 {
552   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
553   rtx offset, base, indexexp, tmp;
554   int scale;
555   extern int flag_pic;
556
557   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
558     {
559       fprintf (file, "tos");
560       return;
561     }
562
563   offset = NULL;
564   base = NULL;
565   indexexp = NULL;
566   while (addr != NULL)
567     {
568       if (GET_CODE (addr) == PLUS)
569         {
570           if (GET_CODE (XEXP (addr, 0)) == PLUS)
571             {
572               tmp = XEXP (addr, 1);
573               addr = XEXP (addr, 0);
574             }
575           else
576             {
577               tmp = XEXP (addr,0);
578               addr = XEXP (addr,1);
579             }
580         }
581       else
582         {
583           tmp = addr;
584           addr = NULL;
585         }
586       switch (GET_CODE (tmp))
587         {
588         case PLUS:
589           abort ();
590         case MEM:
591           if (base)
592             {
593               indexexp = base;
594               base = tmp;
595             }
596           else
597             base = tmp;
598           break;
599         case REG:
600           if (REGNO (tmp) < 8)
601             if (base)
602               {
603                 indexexp = tmp;
604               }
605             else
606               base = tmp;
607           else
608             if (base)
609               {
610                 indexexp = base;
611                 base = tmp;
612               }
613             else
614               base = tmp;
615           break;
616         case MULT:
617           indexexp = tmp;
618           break;
619         case SYMBOL_REF:
620           if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
621               && ! SYMBOL_REF_FLAG (tmp))
622             {
623               if (base)
624                 {
625                   if (indexexp)
626                     abort ();
627                   indexexp = base;
628                 }
629               base = tmp;
630               break;
631             }
632         case CONST:
633           if (flag_pic && GET_CODE (tmp) == CONST)
634             {
635               rtx sym, off, tmp1;
636               tmp1 = XEXP (tmp,0);
637               if (GET_CODE (tmp1)  != PLUS)
638                 abort ();
639
640               sym = XEXP (tmp1,0);
641               if (GET_CODE (sym) != SYMBOL_REF)
642                 {
643                   off = sym;
644                   sym = XEXP (tmp1,1);
645                 }
646               else
647                 off = XEXP (tmp1,1);
648               if (GET_CODE (sym) == SYMBOL_REF)
649                 {
650                   if (GET_CODE (off) != CONST_INT)
651                     abort ();
652
653                   if (CONSTANT_POOL_ADDRESS_P (sym)
654                       || SYMBOL_REF_FLAG (sym))
655                     {
656                       SYMBOL_REF_FLAG (tmp) = 1;
657                     }
658                   else
659                     {
660                       if (base)
661                         {
662                           if (indexexp)
663                             abort ();
664
665                           indexexp = base;
666                         }
667
668                       if (offset != 0)
669                         abort ();
670
671                       base = sym;
672                       offset = off;
673                       break;
674                     }
675                 }
676             }
677         case CONST_INT:
678         case LABEL_REF:
679           if (offset)
680             offset = gen_rtx (PLUS, SImode, tmp, offset);
681           else
682             offset = tmp;
683           break;
684         default:
685           abort ();
686         }
687     }
688   if (! offset)
689     offset = const0_rtx;
690
691   if (base
692 #ifndef INDEX_RATHER_THAN_BASE
693       && (flag_pic || TARGET_HIMEM)
694       && GET_CODE (base) != SYMBOL_REF 
695       && GET_CODE (offset) != CONST_INT
696 #else
697   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
698 #endif
699       && !indexexp && GET_CODE (base) == REG
700       && REG_OK_FOR_INDEX_P (base))
701     {
702       indexexp = base;
703       base = NULL;
704     }
705
706   /* now, offset, base and indexexp are set */
707 #ifndef BASE_REG_NEEDED
708   if (! base)
709     {
710 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
711       if (GET_CODE (offset) == CONST_INT)
712 #endif
713         PUT_ABSOLUTE_PREFIX (file);
714     }
715 #endif
716
717   output_addr_const (file, offset);
718   if (base) /* base can be (REG ...) or (MEM ...) */
719     switch (GET_CODE (base))
720       {
721         /* now we must output base.  Possible alternatives are:
722            (rN)       (REG ...)
723            (sp)       (REG ...)
724            (fp)       (REG ...)
725            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
726            (disp(fp)) (MEM ...)       just before possible [rX:y]
727            (disp(sp)) (MEM ...)
728            (disp(sb)) (MEM ...)
729            */
730       case REG:
731         fprintf (file, "(%s)", reg_names[REGNO (base)]);
732         break;
733       case SYMBOL_REF:
734         if (! flag_pic)
735           abort ();
736
737         fprintf (file, "(");
738         output_addr_const (file, base);
739         fprintf (file, "(sb))");
740         break;
741       case MEM:
742         addr = XEXP(base,0);
743         base = NULL;
744         offset = NULL;
745         while (addr != NULL)
746           {
747             if (GET_CODE (addr) == PLUS)
748               {
749                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
750                   {
751                     tmp = XEXP (addr, 1);
752                     addr = XEXP (addr, 0);
753                   }
754                 else
755                   {
756                     tmp = XEXP (addr, 0);
757                     addr = XEXP (addr, 1);
758                   }
759               }
760             else
761               {
762                 tmp = addr;
763                 addr = NULL;
764               }
765             switch (GET_CODE (tmp))
766               {
767               case REG:
768                 base = tmp;
769                 break;
770               case CONST:
771               case CONST_INT:
772               case SYMBOL_REF:
773               case LABEL_REF:
774                 if (offset)
775                   offset = gen_rtx (PLUS, SImode, tmp, offset);
776                 else
777                   offset = tmp;
778                 break;
779               default:
780                 abort ();
781               }
782           }
783         if (! offset)
784           offset = const0_rtx;
785         fprintf (file, "(");
786         output_addr_const (file, offset);
787         if (base)
788           fprintf (file, "(%s)", reg_names[REGNO (base)]);
789         else if (TARGET_SB)
790           fprintf (file, "(sb)");
791         else
792           abort ();
793         fprintf (file, ")");
794         break;
795       default:
796         abort ();
797       }
798 #ifdef PC_RELATIVE
799   else if (GET_CODE (offset) != CONST_INT)
800     fprintf (file, "(pc)");
801 #ifdef BASE_REG_NEEDED
802   else if (TARGET_SB)
803     fprintf (file, "(sb)");
804   else
805     abort ();
806 #endif
807 #endif /* PC_RELATIVE */
808
809   /* now print index if we have one */
810   if (indexexp)
811     {
812       if (GET_CODE (indexexp) == MULT)
813         {
814           scale = INTVAL (XEXP (indexexp, 1)) >> 1;
815           indexexp = XEXP (indexexp, 0);
816         }
817       else
818         scale = 0;
819       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
820         abort ();
821
822 #ifdef UTEK_ASM
823       fprintf (file, "[%c`%s]",
824                scales[scale],
825                reg_names[REGNO (indexexp)]);
826 #else
827       fprintf (file, "[%s:%c]",
828                reg_names[REGNO (indexexp)],
829                scales[scale]);
830 #endif
831     }
832 }
833 \f
834 /* National 32032 shifting is so bad that we can get
835    better performance in many common cases by using other
836    techniques.  */
837 char *
838 output_shift_insn (operands)
839      rtx *operands;
840 {
841   if (GET_CODE (operands[2]) == CONST_INT
842       && INTVAL (operands[2]) > 0
843       && INTVAL (operands[2]) <= 3)
844     if (GET_CODE (operands[0]) == REG)
845       {
846         if (GET_CODE (operands[1]) == REG)
847           {
848             if (REGNO (operands[0]) == REGNO (operands[1]))
849               {
850                 if (operands[2] == const1_rtx)
851                   return "addd %0,%0";
852                 else if (INTVAL (operands[2]) == 2)
853                   return "addd %0,%0\n\taddd %0,%0";
854               }
855             if (operands[2] == const1_rtx)
856               return "movd %1,%0\n\taddd %0,%0";
857             
858             operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
859             return "addr %a1,%0";
860           }
861         if (operands[2] == const1_rtx)
862           return "movd %1,%0\n\taddd %0,%0";
863       }
864     else if (GET_CODE (operands[1]) == REG)
865       {
866         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
867         return "addr %a1,%0";
868       }
869     else if (INTVAL (operands[2]) == 1
870              && GET_CODE (operands[1]) == MEM
871              && rtx_equal_p (operands [0], operands[1]))
872       {
873         rtx temp = XEXP (operands[1], 0);
874         
875         if (GET_CODE (temp) == REG
876             || (GET_CODE (temp) == PLUS
877                 && GET_CODE (XEXP (temp, 0)) == REG
878                 && GET_CODE (XEXP (temp, 1)) == CONST_INT))
879           return "addd %0,%0";
880       }
881     else return "ashd %2,%0";
882   return "ashd %2,%0";
883 }
884
885 char *
886 output_move_dconst (n, s)
887         int n;
888         char *s;
889 {
890   static char r[32];
891
892   if (n > -9 && n < 8)
893     strcpy (r, "movqd ");
894   else if (n > 0 && n < 256)
895     strcpy (r, "movzbd ");
896   else if (n > 0 && n < 65536)
897     strcpy (r, "movzwd ");
898   else if (n < 0 && n > -129)
899     strcpy (r, "movxbd ");
900   else if (n < 0 && n > -32769)
901     strcpy (r, "movxwd ");
902   else
903     strcpy (r, "movd ");
904   strcat (r, s);
905   return r;
906 }