OSDN Git Service

(print_operand): Integer CONST_DOUBLE is DImode.
[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_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     split_double (operands[1], &operands[1], &latehalf[1]);
302   else
303     latehalf[1] = operands[1];
304
305   /* If insn is effectively movd N(sp),tos then we will do the
306      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
307      for the low word as well, to compensate for the first decrement of sp.
308      Given this, it doesn't matter which half we do "first".  */
309   if (optype0 == PUSHOP
310       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
311       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
312     operands[1] = latehalf[1];
313
314   /* If one or both operands autodecrementing,
315      do the two words, high-numbered first.  */
316   else if (optype0 == PUSHOP || optype1 == PUSHOP)
317     {
318       output_asm_insn (singlemove_string (latehalf), latehalf);
319       return singlemove_string (operands);
320     }
321
322   /* If the first move would clobber the source of the second one,
323      do them in the other order.  */
324
325   /* Overlapping registers.  */
326   if (optype0 == REGOP && optype1 == REGOP
327       && REGNO (operands[0]) == REGNO (latehalf[1]))
328     {
329       /* Do that word.  */
330       output_asm_insn (singlemove_string (latehalf), latehalf);
331       /* Do low-numbered word.  */
332       return singlemove_string (operands);
333     }
334   /* Loading into a register which overlaps a register used in the address.  */
335   else if (optype0 == REGOP && optype1 != REGOP
336            && reg_overlap_mentioned_p (operands[0], operands[1]))
337     {
338       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
339           && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
340         {
341           /* If both halves of dest are used in the src memory address,
342              load the destination address into the low reg (operands[0]).
343              Then it works to load latehalf first.  */
344           rtx xops[2];
345           xops[0] = XEXP (operands[1], 0);
346           xops[1] = operands[0];
347           output_asm_insn ("addr %a0,%1", xops);
348           operands[1] = gen_rtx (MEM, DImode, operands[0]);
349           latehalf[1] = adj_offsettable_operand (operands[1], 4);
350           /* The first half has the overlap, Do the late half first.  */
351           output_asm_insn (singlemove_string (latehalf), latehalf);
352           /* Then clobber.  */
353           return singlemove_string (operands);
354         }
355       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
356         {
357           /* The first half has the overlap, Do the late half first.  */
358           output_asm_insn (singlemove_string (latehalf), latehalf);
359           /* Then clobber.  */
360           return singlemove_string (operands);
361         }
362     }
363
364   /* Normal case.  Do the two words, low-numbered first.  */
365
366   output_asm_insn (singlemove_string (operands), operands);
367
368   operands[0] = latehalf[0];
369   operands[1] = latehalf[1];
370   return singlemove_string (operands);
371 }
372
373 int
374 check_reg (oper, reg)
375      rtx oper;
376      int reg;
377 {
378   register int i;
379
380   if (oper == 0)
381     return 0;
382   switch (GET_CODE(oper))
383     {
384     case REG:
385       return (REGNO(oper) == reg) ? 1 : 0;
386     case MEM:
387       return check_reg(XEXP(oper, 0), reg);
388     case PLUS:
389     case MULT:
390       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
391     }
392   return 0;
393 }
394
395 /* Returns 1 if OP contains a global symbol reference */
396
397 int
398 global_symbolic_reference_mentioned_p (op, f)
399      rtx op;
400      int f;
401 {
402   register char *fmt;
403   register int i;
404
405   if (GET_CODE (op) == SYMBOL_REF)
406     {
407       if (! SYMBOL_REF_FLAG (op))
408         return 1;
409       else
410         return 0;
411     }
412   else if (f && GET_CODE (op) != CONST)
413     return 0;
414
415   fmt = GET_RTX_FORMAT (GET_CODE (op));
416   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
417     {
418       if (fmt[i] == 'E')
419         {
420           register int j;
421
422           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
423             if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0))
424               return 1;
425         }
426       else if (fmt[i] == 'e' 
427                && global_symbolic_reference_mentioned_p (XEXP (op, i), 0))
428         return 1;
429     }
430
431   return 0;
432 }
433
434 \f
435 /* PRINT_OPERAND is defined to call this function,
436    which is easier to debug than putting all the code in
437    a macro definition in ns32k.h.  */
438
439 void
440 print_operand (file, x, code)
441      FILE *file;
442      rtx x;
443      char code;
444 {
445   if (code == '$')
446     PUT_IMMEDIATE_PREFIX (file);
447   else if (code == '?')
448     PUT_EXTERNAL_PREFIX (file);
449   else if (GET_CODE (x) == REG)
450     fprintf (file, "%s", reg_names[REGNO (x)]);
451   else if (GET_CODE (x) == MEM)
452     {
453       rtx tmp = XEXP (x, 0);
454 #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
455       if (GET_CODE (tmp) != CONST_INT)
456         {
457           char *out = XSTR (tmp, 0);
458           if (out[0] == '*')
459             {
460               PUT_ABSOLUTE_PREFIX (file);
461               fprintf (file, "%s", &out[1]);
462             }
463           else
464             ASM_OUTPUT_LABELREF (file, out);
465         }
466       else
467 #endif
468         output_address (XEXP (x, 0));
469     }
470   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
471     {
472       if (GET_MODE (x) == DFmode)
473         { 
474           union { double d; int i[2]; } u;
475           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
476           PUT_IMMEDIATE_PREFIX(file);
477 #ifdef SEQUENT_ASM
478           /* Sequent likes it's floating point constants as integers */
479           fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
480 #else
481 #ifdef ENCORE_ASM
482           fprintf (file, "0f%.20e", u.d); 
483 #else
484           fprintf (file, "0d%.20e", u.d); 
485 #endif
486 #endif
487         }
488       else
489         { 
490           union { double d; int i[2]; } u;
491           u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
492           PUT_IMMEDIATE_PREFIX (file);
493 #ifdef SEQUENT_ASM
494           /* We have no way of winning if we can't get the bits
495              for a sequent floating point number.  */
496 #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
497           abort ();
498 #endif
499           {
500             union { float f; long l; } uu;
501             uu.f = u.d;
502             fprintf (file, "0Fx%08x", uu.l);
503           }
504 #else
505           fprintf (file, "0f%.20e", u.d); 
506 #endif
507         }
508     }
509   else
510     {
511 #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
512       if (GET_CODE (x) == CONST_INT)
513 #endif
514         PUT_IMMEDIATE_PREFIX (file);
515       output_addr_const (file, x);
516     }
517 }
518 \f
519 /* PRINT_OPERAND_ADDRESS is defined to call this function,
520    which is easier to debug than putting all the code in
521    a macro definition in ns32k.h .  */
522
523 /* Completely rewritten to get this to work with Gas for PC532 Mach.
524    This function didn't work and I just wasn't able (nor very willing) to
525    figure out how it worked.
526    90-11-25 Tatu Yl|nen <ylo@cs.hut.fi> */
527
528 print_operand_address (file, addr)
529      register FILE *file;
530      register rtx addr;
531 {
532   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
533   rtx offset, base, indexexp, tmp;
534   int scale;
535   extern int flag_pic;
536
537   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
538     {
539       fprintf (file, "tos");
540       return;
541     }
542
543   offset = NULL;
544   base = NULL;
545   indexexp = NULL;
546   while (addr != NULL)
547     {
548       if (GET_CODE (addr) == PLUS)
549         {
550           if (GET_CODE (XEXP (addr, 0)) == PLUS)
551             {
552               tmp = XEXP (addr, 1);
553               addr = XEXP (addr, 0);
554             }
555           else
556             {
557               tmp = XEXP (addr,0);
558               addr = XEXP (addr,1);
559             }
560         }
561       else
562         {
563           tmp = addr;
564           addr = NULL;
565         }
566       switch (GET_CODE (tmp))
567         {
568         case PLUS:
569           abort ();
570         case MEM:
571           if (base)
572             {
573               indexexp = base;
574               base = tmp;
575             }
576           else
577             base = tmp;
578           break;
579         case REG:
580           if (REGNO (tmp) < 8)
581             if (base)
582               {
583                 indexexp = tmp;
584               }
585             else
586               base = tmp;
587           else
588             if (base)
589               {
590                 indexexp = base;
591                 base = tmp;
592               }
593             else
594               base = tmp;
595           break;
596         case MULT:
597           indexexp = tmp;
598           break;
599         case SYMBOL_REF:
600           if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp)
601               && ! SYMBOL_REF_FLAG (tmp))
602             {
603               if (base)
604                 {
605                   if (indexexp)
606                     abort ();
607                   indexexp = base;
608                 }
609               base = tmp;
610               break;
611             }
612         case CONST:
613           if (flag_pic && GET_CODE (tmp) == CONST)
614             {
615               rtx sym, off, tmp1;
616               tmp1 = XEXP (tmp,0);
617               if (GET_CODE (tmp1)  != PLUS)
618         abort ();
619
620               sym = XEXP (tmp1,0);
621               if (GET_CODE (sym) != SYMBOL_REF)
622                 {
623                   off = sym;
624                   sym = XEXP (tmp1,1);
625                 }
626               else
627                 off = XEXP (tmp1,1);
628               if (GET_CODE (sym) == SYMBOL_REF)
629                 {
630                   if (GET_CODE (off) != CONST_INT)
631                     abort ();
632
633                   if (CONSTANT_POOL_ADDRESS_P (sym)
634                       || SYMBOL_REF_FLAG (sym))
635                     {
636                       SYMBOL_REF_FLAG (tmp) = 1;
637                     }
638                   else
639                     {
640                       if (base)
641                         {
642                           if (indexexp)
643                             abort ();
644
645                           indexexp = base;
646                         }
647
648                       if (offset != 0)
649                         abort ();
650
651                       base = sym;
652                       offset = off;
653                       break;
654                     }
655                 }
656             }
657         case CONST_INT:
658         case LABEL_REF:
659           if (offset)
660             offset = gen_rtx (PLUS, SImode, tmp, offset);
661           else
662             offset = tmp;
663           break;
664         default:
665           abort ();
666         }
667     }
668   if (! offset)
669     offset = const0_rtx;
670
671   if (base
672 #ifndef INDEX_RATHER_THAN_BASE
673       && flag_pic 
674       && GET_CODE (base) != SYMBOL_REF 
675       && GET_CODE (offset) != CONST_INT
676 #else
677   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
678 #endif
679       && !indexexp && GET_CODE (base) == REG
680       && REG_OK_FOR_INDEX_P (base))
681     {
682       indexexp = base;
683       base = NULL;
684     }
685
686   /* now, offset, base and indexexp are set */
687   if (! base)
688     {
689 #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
690       if (GET_CODE (offset) == CONST_INT)
691 /*      if (! (GET_CODE (offset) == LABEL_REF
692              || GET_CODE (offset) == SYMBOL_REF)) */
693 #endif
694         PUT_ABSOLUTE_PREFIX (file);
695     }
696
697   output_addr_const (file, offset);
698   if (base) /* base can be (REG ...) or (MEM ...) */
699     switch (GET_CODE (base))
700       {
701         /* now we must output base.  Possible alternatives are:
702            (rN)       (REG ...)
703            (sp)       (REG ...)
704            (fp)       (REG ...)
705            (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
706            (disp(fp)) (MEM ...)       just before possible [rX:y]
707            (disp(sp)) (MEM ...)
708            (disp(sb)) (MEM ...)
709            */
710       case REG:
711         fprintf (file, "(%s)", reg_names[REGNO (base)]);
712         break;
713       case SYMBOL_REF:
714           if (! flag_pic)
715             abort ();
716
717         fprintf (file, "(");
718         output_addr_const (file, base);
719         fprintf (file, "(sb))");
720         break;
721       case MEM:
722         addr = XEXP(base,0);
723         base = NULL;
724         offset = NULL;
725         while (addr != NULL)
726           {
727             if (GET_CODE (addr) == PLUS)
728               {
729                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
730                   {
731                     tmp = XEXP (addr, 1);
732                     addr = XEXP (addr, 0);
733                   }
734                 else
735                   {
736                     tmp = XEXP (addr, 0);
737                     addr = XEXP (addr, 1);
738                   }
739               }
740             else
741               {
742                 tmp = addr;
743                 addr = NULL;
744               }
745             switch (GET_CODE (tmp))
746               {
747               case REG:
748                 base = tmp;
749                 break;
750               case CONST:
751               case CONST_INT:
752               case SYMBOL_REF:
753               case LABEL_REF:
754                 if (offset)
755                   offset = gen_rtx (PLUS, SImode, tmp, offset);
756                 else
757                   offset = tmp;
758                 break;
759               default:
760                 abort ();
761               }
762           }
763         if (! offset)
764           offset = const0_rtx;
765         fprintf (file, "(");
766         output_addr_const (file, offset);
767         if (base)
768           fprintf (file, "(%s)", reg_names[REGNO (base)]);
769 #ifdef BASE_REG_NEEDED
770   else 
771     {
772       /* Abs. addresses don't need a base (I think). */
773       if (GET_CODE (offset) != CONST_INT
774 #ifndef PC_RELATIVE
775           && GET_CODE (offset) != LABEL_REF
776           && GET_CODE (offset) != SYMBOL_REF
777           && GET_CODE (offset) != CONST
778           && GET_CODE (offset) != PLUS
779 #endif
780          )
781         {
782           if (TARGET_SB)
783             fprintf (file, "(sb)");
784           else
785             abort ();
786         }
787     }
788 #endif
789         fprintf (file, ")");
790         break;
791
792       default:
793         abort ();
794       }
795 #ifdef PC_RELATIVE
796   else if (GET_CODE (offset) == LABEL_REF
797            || GET_CODE (offset) == SYMBOL_REF
798            || GET_CODE (offset) == CONST
799            || GET_CODE (offset) == PLUS)
800     fprintf (file, "(pc)");
801 #endif
802 #ifdef BASE_REG_NEEDED          /* this is defined if the assembler always
803                                    needs a base register */
804     else if (TARGET_SB)
805       fprintf (file, "(sb)");
806     else
807       abort ();
808 #endif
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 }