|
|
1.1 root 1: /* Subroutines for assembler code output on the NS32000.
2: Copyright (C) 1988 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:
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: /* PRINT_OPERAND is defined to call this function,
401: which is easier to debug than putting all the code in
402: a macro definition in ns32k.h. */
403:
404: void
405: print_operand (file, x, code)
406: FILE *file;
407: rtx x;
408: char code;
409: {
410: if (code == '$')
411: PUT_IMMEDIATE_PREFIX (file);
412: else if (code == '?')
413: PUT_EXTERNAL_PREFIX (file);
414: else if (GET_CODE (x) == REG)
415: fprintf (file, "%s", reg_names[REGNO (x)]);
416: else if (GET_CODE (x) == MEM)
417: {
418: rtx tmp = XEXP (x, 0);
419: #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
420: if (GET_CODE (tmp) != CONST_INT)
421: {
422: char *out = XSTR (tmp, 0);
423: if (out[0] == '*')
424: {
425: PUT_ABSOLUTE_PREFIX (file);
426: fprintf (file, "%s", &out[1]);
427: }
428: else
429: ASM_OUTPUT_LABELREF (file, out);
430: }
431: else
432: #endif
433: output_address (XEXP (x, 0));
434: }
435: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
436: {
437: if (GET_MODE (x) == DFmode)
438: {
439: union { double d; int i[2]; } u;
440: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
441: PUT_IMMEDIATE_PREFIX(file);
442: #ifdef SEQUENT_ASM
443: /* Sequent likes it's floating point constants as integers */
444: fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
445: #else
446: #ifdef ENCORE_ASM
447: fprintf (file, "0f%.20e", u.d);
448: #else
449: fprintf (file, "0d%.20e", u.d);
450: #endif
451: #endif
452: }
453: else
454: {
455: union { double d; int i[2]; } u;
456: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
457: PUT_IMMEDIATE_PREFIX (file);
458: #ifdef SEQUENT_ASM
459: /* We have no way of winning if we can't get the bits
460: for a sequent floating point number. */
461: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
462: abort ();
463: #endif
464: {
465: union { float f; long l; } uu;
466: uu.f = u.d;
467: fprintf (file, "0Fx%08x", uu.l);
468: }
469: #else
470: fprintf (file, "0f%.20e", u.d);
471: #endif
472: }
473: }
474: else
475: {
476: #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
477: if (GET_CODE (x) == CONST_INT)
478: #endif
479: PUT_IMMEDIATE_PREFIX (file);
480: output_addr_const (file, x);
481: }
482: }
483:
484: /* PRINT_OPERAND_ADDRESS is defined to call this function,
485: which is easier to debug than putting all the code in
486: a macro definition in ns32k.h . */
487:
488: /* Completely rewritten to get this to work with Gas for PC532 Mach.
489: This function didn't work and I just wasn't able (nor very willing) to
490: figure out how it worked.
491: 90-11-25 Tatu Yl|nen <[email protected]> */
492:
493: print_operand_address (file, addr)
494: register FILE *file;
495: register rtx addr;
496: {
497: static char scales[] = { 'b', 'w', 'd', 0, 'q', };
498: rtx offset, base, indexexp, tmp;
499: int scale;
500:
501: if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
502: {
503: fprintf (file, "tos");
504: return;
505: }
506:
507: offset = NULL;
508: base = NULL;
509: indexexp = NULL;
510: while (addr != NULL)
511: {
512: if (GET_CODE (addr) == PLUS)
513: {
514: if (GET_CODE (XEXP (addr, 0)) == PLUS)
515: {
516: tmp = XEXP (addr, 1);
517: addr = XEXP (addr, 0);
518: }
519: else
520: {
521: tmp = XEXP (addr,0);
522: addr = XEXP (addr,1);
523: }
524: }
525: else
526: {
527: tmp = addr;
528: addr = NULL;
529: }
530: switch (GET_CODE (tmp))
531: {
532: case PLUS:
533: abort ();
534: case MEM:
535: if (base)
536: {
537: indexexp = base;
538: base = tmp;
539: }
540: else
541: base = tmp;
542: break;
543: case REG:
544: if (REGNO (tmp) < 8)
545: if (base)
546: {
547: indexexp = tmp;
548: }
549: else
550: base = tmp;
551: else
552: if (base)
553: {
554: indexexp = base;
555: base = tmp;
556: }
557: else
558: base = tmp;
559: break;
560: case MULT:
561: indexexp = tmp;
562: break;
563: case CONST:
564: case CONST_INT:
565: case SYMBOL_REF:
566: case LABEL_REF:
567: if (offset)
568: offset = gen_rtx (PLUS, SImode, tmp, offset);
569: else
570: offset = tmp;
571: break;
572: default:
573: abort ();
574: }
575: }
576: if (! offset)
577: offset = const0_rtx;
578:
579: #ifdef INDEX_RATHER_THAN_BASE
580: /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
581: if (base && !indexexp && GET_CODE (base) == REG
582: && REG_OK_FOR_INDEX_P (base))
583: {
584: indexexp = base;
585: base = 0;
586: }
587: #endif
588:
589: /* now, offset, base and indexexp are set */
590: if (! base)
591: {
592: #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
593: if (GET_CODE (offset) == CONST_INT)
594: /* if (! (GET_CODE (offset) == LABEL_REF
595: || GET_CODE (offset) == SYMBOL_REF)) */
596: #endif
597: PUT_ABSOLUTE_PREFIX (file);
598: }
599:
600: output_addr_const (file, offset);
601: if (base) /* base can be (REG ...) or (MEM ...) */
602: switch (GET_CODE (base))
603: {
604: /* now we must output base. Possible alternatives are:
605: (rN) (REG ...)
606: (sp) (REG ...)
607: (fp) (REG ...)
608: (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
609: (disp(fp)) (MEM ...) just before possible [rX:y]
610: (disp(sp)) (MEM ...)
611: (disp(sb)) (MEM ...)
612: */
613: case REG:
614: fprintf (file, "(%s)", reg_names[REGNO (base)]);
615: break;
616: case MEM:
617: addr = XEXP(base,0);
618: base = NULL;
619: offset = NULL;
620: while (addr != NULL)
621: {
622: if (GET_CODE (addr) == PLUS)
623: {
624: if (GET_CODE (XEXP (addr, 0)) == PLUS)
625: {
626: tmp = XEXP (addr, 1);
627: addr = XEXP (addr, 0);
628: }
629: else
630: {
631: tmp = XEXP (addr, 0);
632: addr = XEXP (addr, 1);
633: }
634: }
635: else
636: {
637: tmp = addr;
638: addr = NULL;
639: }
640: switch (GET_CODE (tmp))
641: {
642: case REG:
643: base = tmp;
644: break;
645: case CONST:
646: case CONST_INT:
647: case SYMBOL_REF:
648: case LABEL_REF:
649: if (offset)
650: offset = gen_rtx (PLUS, SImode, tmp, offset);
651: else
652: offset = tmp;
653: break;
654: default:
655: abort ();
656: }
657: }
658: if (! offset)
659: offset = const0_rtx;
660: fprintf (file, "(");
661: output_addr_const (file, offset);
662: if (base)
663: fprintf (file, "(%s)", reg_names[REGNO (base)]);
664: #ifdef BASE_REG_NEEDED
665: else if (TARGET_SB)
666: fprintf (file, "(sb)");
667: else
668: abort ();
669: #endif
670: fprintf (file, ")");
671: break;
672:
673: default:
674: abort ();
675: }
676: #ifdef PC_RELATIVE
677: else /* no base */
678: if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
679: fprintf (file, "(pc)");
680: #endif
681: #ifdef BASE_REG_NEEDED /* this is defined if the assembler always
682: needs a base register */
683: else if (TARGET_SB)
684: fprintf (file, "(sb)");
685: else
686: abort ();
687: #endif
688: /* now print index if we have one */
689: if (indexexp)
690: {
691: if (GET_CODE (indexexp) == MULT)
692: {
693: scale = INTVAL (XEXP (indexexp, 1)) >> 1;
694: indexexp = XEXP (indexexp, 0);
695: }
696: else
697: scale = 0;
698: if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
699: abort ();
700:
701: #ifdef UTEK_ASM
702: fprintf (file, "[%c`%s]",
703: scales[scale],
704: reg_names[REGNO (indexexp)]);
705: #else
706: fprintf (file, "[%s:%c]",
707: reg_names[REGNO (indexexp)],
708: scales[scale]);
709: #endif
710: }
711: }
712:
713: /* National 32032 shifting is so bad that we can get
714: better performance in many common cases by using other
715: techniques. */
716: char *
717: output_shift_insn (operands)
718: rtx *operands;
719: {
720: if (GET_CODE (operands[2]) == CONST_INT
721: && INTVAL (operands[2]) > 0
722: && INTVAL (operands[2]) <= 3)
723: if (GET_CODE (operands[0]) == REG)
724: {
725: if (GET_CODE (operands[1]) == REG)
726: {
727: if (REGNO (operands[0]) == REGNO (operands[1]))
728: {
729: if (operands[2] == const1_rtx)
730: return "addd %0,%0";
731: else if (INTVAL (operands[2]) == 2)
732: return "addd %0,%0\n\taddd %0,%0";
733: }
734: if (operands[2] == const1_rtx)
735: return "movd %1,%0\n\taddd %0,%0";
736:
737: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
738: return "addr %a1,%0";
739: }
740: if (operands[2] == const1_rtx)
741: return "movd %1,%0\n\taddd %0,%0";
742: }
743: else if (GET_CODE (operands[1]) == REG)
744: {
745: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
746: return "addr %a1,%0";
747: }
748: else if (INTVAL (operands[2]) == 1
749: && GET_CODE (operands[1]) == MEM
750: && rtx_equal_p (operands [0], operands[1]))
751: {
752: rtx temp = XEXP (operands[1], 0);
753:
754: if (GET_CODE (temp) == REG
755: || (GET_CODE (temp) == PLUS
756: && GET_CODE (XEXP (temp, 0)) == REG
757: && GET_CODE (XEXP (temp, 1)) == CONST_INT))
758: return "addd %0,%0";
759: }
760: else return "ashd %2,%0";
761: return "ashd %2,%0";
762: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.