|
|
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: {
1.1.1.3 root 41: fprintf (stderr, s, s1, s2);
1.1 root 42: }
43:
44: /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
45:
46: int
1.1.1.3 root 47: hard_regno_mode_ok (regno, mode)
48: int regno;
1.1.1.4 ! root 49: enum machine_mode mode;
1.1.1.3 root 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;
1.1 root 86: }
1.1.1.3 root 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: }
1.1.1.4 ! root 110:
! 111: /* Used to abort here, but simply saying "no" handles TImode
! 112: much better. */
! 113: return 0;
1.1 root 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:
1.1.1.3 root 181: /* Constants, memory, and FP registers can go into FP registers. */
1.1 root 182: if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
183: return NO_REGS;
184:
1.1.1.3 root 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:
1.1 root 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
1.1.1.2 root 198: multiplier (for MULT). */
1.1 root 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, POPOP, 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 = POPOP;
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 = POPOP;
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 one or both operands autodecrementing,
311: do the two words, high-numbered first. */
312:
313: if (optype0 == POPOP || optype1 == POPOP)
314: {
315: output_asm_insn (singlemove_string (latehalf), latehalf);
316: return singlemove_string (operands);
317: }
318:
319: /* Not autodecrementing. Do the two words, low-numbered first. */
320:
321: output_asm_insn (singlemove_string (operands), operands);
322:
323: operands[0] = latehalf[0];
324: operands[1] = latehalf[1];
325: return singlemove_string (operands);
326: }
327:
328: int
329: check_reg (oper, reg)
330: rtx oper;
331: int reg;
332: {
333: register int i;
334:
335: if (oper == 0)
336: return 0;
337: switch (GET_CODE(oper))
338: {
339: case REG:
340: return (REGNO(oper) == reg) ? 1 : 0;
341: case MEM:
342: return check_reg(XEXP(oper, 0), reg);
343: case PLUS:
344: case MULT:
345: return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
346: }
347: return 0;
348: }
349:
350: /* PRINT_OPERAND is defined to call this function,
351: which is easier to debug than putting all the code in
352: a macro definition in ns32k.h. */
353:
354: void
355: print_operand (file, x, code)
356: FILE *file;
357: rtx x;
358: char code;
359: {
360: if (code == '$')
1.1.1.3 root 361: PUT_IMMEDIATE_PREFIX (file);
1.1 root 362: else if (code == '?')
1.1.1.3 root 363: PUT_EXTERNAL_PREFIX (file);
1.1 root 364: else if (GET_CODE (x) == REG)
365: fprintf (file, "%s", reg_names[REGNO (x)]);
366: else if (GET_CODE (x) == MEM)
1.1.1.2 root 367: {
368: rtx tmp = XEXP (x, 0);
1.1.1.3 root 369: #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
370: if (GET_CODE (tmp) != CONST_INT)
1.1.1.2 root 371: {
372: char *out = XSTR (tmp, 0);
373: if (out[0] == '*')
1.1.1.3 root 374: {
375: PUT_ABSOLUTE_PREFIX (file);
376: fprintf (file, "%s", &out[1]);
377: }
1.1.1.2 root 378: else
379: ASM_OUTPUT_LABELREF (file, out);
380: }
381: else
382: #endif
383: output_address (XEXP (x, 0));
384: }
1.1 root 385: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
1.1.1.2 root 386: {
387: if (GET_MODE (x) == DFmode)
388: {
389: union { double d; int i[2]; } u;
390: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
391: PUT_IMMEDIATE_PREFIX(file);
392: #ifdef SEQUENT_ASM
393: /* Sequent likes it's floating point constants as integers */
1.1.1.3 root 394: fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
1.1.1.2 root 395: #else
396: #ifdef ENCORE_ASM
397: fprintf (file, "0f%.20e", u.d);
398: #else
399: fprintf (file, "0d%.20e", u.d);
400: #endif
401: #endif
402: }
403: else
404: {
405: union { double d; int i[2]; } u;
406: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
1.1.1.3 root 407: PUT_IMMEDIATE_PREFIX (file);
1.1.1.2 root 408: #ifdef SEQUENT_ASM
1.1.1.3 root 409: /* We have no way of winning if we can't get the bits
410: for a sequent floating point number. */
411: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
412: abort ();
413: #endif
1.1.1.2 root 414: {
415: union { float f; long l; } uu;
416: uu.f = u.d;
417: fprintf (file, "0Fx%08x", uu.l);
418: }
419: #else
420: fprintf (file, "0f%.20e", u.d);
421: #endif
422: }
423: }
1.1 root 424: else
425: {
1.1.1.4 ! root 426: #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
1.1.1.3 root 427: if (GET_CODE (x) == CONST_INT)
428: #endif
1.1.1.4 ! root 429: PUT_IMMEDIATE_PREFIX (file);
1.1 root 430: output_addr_const (file, x);
431: }
432: }
433:
434: /* PRINT_OPERAND_ADDRESS is defined to call this function,
435: which is easier to debug than putting all the code in
436: a macro definition in ns32k.h . */
437:
438: /* Completely rewritten to get this to work with Gas for PC532 Mach.
439: This function didn't work and I just wasn't able (nor very willing) to
440: figure out how it worked.
441: 90-11-25 Tatu Yl|nen <[email protected]> */
442:
443: print_operand_address (file, addr)
444: register FILE *file;
445: register rtx addr;
446: {
447: static char scales[] = { 'b', 'w', 'd', 0, 'q', };
448: rtx offset, base, indexexp, tmp;
449: int scale;
450:
451: if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
452: {
453: fprintf (file, "tos");
454: return;
455: }
456:
457: offset = NULL;
458: base = NULL;
459: indexexp = NULL;
460: while (addr != NULL)
461: {
462: if (GET_CODE (addr) == PLUS)
463: {
464: if (GET_CODE (XEXP (addr, 0)) == PLUS)
465: {
466: tmp = XEXP (addr, 1);
467: addr = XEXP (addr, 0);
468: }
469: else
470: {
471: tmp = XEXP (addr,0);
472: addr = XEXP (addr,1);
473: }
474: }
475: else
476: {
477: tmp = addr;
478: addr = NULL;
479: }
480: switch (GET_CODE (tmp))
481: {
482: case PLUS:
483: abort ();
484: case MEM:
485: if (base)
486: {
487: indexexp = base;
488: base = tmp;
489: }
490: else
491: base = tmp;
492: break;
493: case REG:
494: if (REGNO (tmp) < 8)
495: if (base)
496: {
497: indexexp = tmp;
498: }
499: else
500: base = tmp;
501: else
502: if (base)
503: {
504: indexexp = base;
505: base = tmp;
506: }
507: else
508: base = tmp;
509: break;
510: case MULT:
511: indexexp = tmp;
512: break;
513: case CONST:
514: case CONST_INT:
515: case SYMBOL_REF:
516: case LABEL_REF:
517: if (offset)
518: offset = gen_rtx (PLUS, SImode, tmp, offset);
519: else
520: offset = tmp;
521: break;
522: default:
523: abort ();
524: }
525: }
526: if (! offset)
527: offset = const0_rtx;
1.1.1.3 root 528:
529: #ifdef INDEX_RATHER_THAN_BASE
530: /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
531: if (base && !indexexp && GET_CODE (base) == REG
1.1.1.4 ! root 532: && REG_OK_FOR_INDEX_P (base))
1.1.1.3 root 533: {
534: indexexp = base;
535: base = 0;
536: }
537: #endif
538:
1.1 root 539: /* now, offset, base and indexexp are set */
540: if (! base)
541: {
1.1.1.2 root 542: #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1.1.1.3 root 543: if (GET_CODE (offset) == CONST_INT)
544: /* if (! (GET_CODE (offset) == LABEL_REF
545: || GET_CODE (offset) == SYMBOL_REF)) */
1.1 root 546: #endif
547: PUT_ABSOLUTE_PREFIX (file);
548: }
549:
1.1.1.2 root 550: output_addr_const (file, offset);
1.1 root 551: if (base) /* base can be (REG ...) or (MEM ...) */
552: switch (GET_CODE (base))
553: {
554: /* now we must output base. Possible alternatives are:
555: (rN) (REG ...)
1.1.1.3 root 556: (sp) (REG ...)
1.1 root 557: (fp) (REG ...)
558: (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
559: (disp(fp)) (MEM ...) just before possible [rX:y]
560: (disp(sp)) (MEM ...)
561: (disp(sb)) (MEM ...)
562: */
563: case REG:
564: fprintf (file, "(%s)", reg_names[REGNO (base)]);
565: break;
566: case MEM:
567: addr = XEXP(base,0);
568: base = NULL;
569: offset = NULL;
570: while (addr != NULL)
571: {
572: if (GET_CODE (addr) == PLUS)
573: {
574: if (GET_CODE (XEXP (addr, 0)) == PLUS)
575: {
576: tmp = XEXP (addr, 1);
577: addr = XEXP (addr, 0);
578: }
579: else
580: {
581: tmp = XEXP (addr, 0);
582: addr = XEXP (addr, 1);
583: }
584: }
585: else
586: {
587: tmp = addr;
588: addr = NULL;
589: }
590: switch (GET_CODE (tmp))
591: {
592: case REG:
593: base = tmp;
594: break;
595: case CONST:
596: case CONST_INT:
597: case SYMBOL_REF:
598: case LABEL_REF:
599: if (offset)
600: offset = gen_rtx (PLUS, SImode, tmp, offset);
601: else
602: offset = tmp;
603: break;
604: default:
605: abort ();
606: }
607: }
608: if (! offset)
609: offset = const0_rtx;
610: fprintf (file, "(");
611: output_addr_const (file, offset);
612: if (base)
613: fprintf (file, "(%s)", reg_names[REGNO (base)]);
1.1.1.2 root 614: #ifdef BASE_REG_NEEDED
1.1 root 615: else if (TARGET_SB)
616: fprintf (file, "(sb)");
617: else
618: abort ();
1.1.1.2 root 619: #endif
1.1 root 620: fprintf (file, ")");
621: break;
622:
623: default:
624: abort ();
625: }
626: #ifdef PC_RELATIVE
627: else /* no base */
628: if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
629: fprintf (file, "(pc)");
630: #endif
631: #ifdef BASE_REG_NEEDED /* this is defined if the assembler always
632: needs a base register */
633: else if (TARGET_SB)
634: fprintf (file, "(sb)");
635: else
636: abort ();
637: #endif
638: /* now print index if we have one */
639: if (indexexp)
640: {
641: if (GET_CODE (indexexp) == MULT)
642: {
643: scale = INTVAL (XEXP (indexexp, 1)) >> 1;
644: indexexp = XEXP (indexexp, 0);
645: }
646: else
647: scale = 0;
648: if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
649: abort ();
650:
1.1.1.3 root 651: #ifdef UTEK_ASM
652: fprintf (file, "[%c`%s]",
653: scales[scale],
654: reg_names[REGNO (indexexp)]);
655: #else
1.1 root 656: fprintf (file, "[%s:%c]",
657: reg_names[REGNO (indexexp)],
658: scales[scale]);
1.1.1.3 root 659: #endif
1.1 root 660: }
661: }
662:
663: /* National 32032 shifting is so bad that we can get
664: better performance in many common cases by using other
665: techniques. */
666: char *
667: output_shift_insn (operands)
668: rtx *operands;
669: {
670: if (GET_CODE (operands[2]) == CONST_INT
671: && INTVAL (operands[2]) > 0
672: && INTVAL (operands[2]) <= 3)
673: if (GET_CODE (operands[0]) == REG)
674: {
675: if (GET_CODE (operands[1]) == REG)
676: {
677: if (REGNO (operands[0]) == REGNO (operands[1]))
678: {
679: if (operands[2] == const1_rtx)
680: return "addd %0,%0";
681: else if (INTVAL (operands[2]) == 2)
682: return "addd %0,%0\n\taddd %0,%0";
683: }
684: if (operands[2] == const1_rtx)
685: return "movd %1,%0\n\taddd %0,%0";
686:
687: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
688: return "addr %a1,%0";
689: }
690: if (operands[2] == const1_rtx)
691: return "movd %1,%0\n\taddd %0,%0";
692: }
693: else if (GET_CODE (operands[1]) == REG)
694: {
695: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
696: return "addr %a1,%0";
697: }
698: else if (INTVAL (operands[2]) == 1
699: && GET_CODE (operands[1]) == MEM
700: && rtx_equal_p (operands [0], operands[1]))
701: {
702: rtx temp = XEXP (operands[1], 0);
703:
704: if (GET_CODE (temp) == REG
705: || (GET_CODE (temp) == PLUS
706: && GET_CODE (XEXP (temp, 0)) == REG
707: && GET_CODE (XEXP (temp, 1)) == CONST_INT))
708: return "addd %0,%0";
709: }
710: else return "ashd %2,%0";
711: return "ashd %2,%0";
712: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.