|
|
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;
! 49: int 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;
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: }
! 110: abort(0);
1.1 root 111: }
112:
113: /* ADDRESS_COST calls this. This function is not optimal
114: for the 32032 & 32332, but it probably is better than
115: the default. */
116:
117: int
118: calc_address_cost (operand)
119: rtx operand;
120: {
121: int i;
122: int cost = 0;
123:
124: if (GET_CODE (operand) == MEM)
125: cost += 3;
126: if (GET_CODE (operand) == MULT)
127: cost += 2;
128: #if 0
129: if (GET_CODE (operand) == REG)
130: cost += 1; /* not really, but the documentation
131: says different amount of registers
132: shouldn't return the same costs */
133: #endif
134: switch (GET_CODE (operand))
135: {
136: case REG:
137: case CONST:
138: case CONST_INT:
139: case CONST_DOUBLE:
140: case SYMBOL_REF:
141: case LABEL_REF:
142: case POST_DEC:
143: case PRE_DEC:
144: break;
145: case MULT:
146: case MEM:
147: case PLUS:
148: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
149: {
150: cost += calc_address_cost (XEXP (operand, i));
151: }
152: default:
153: break;
154: }
155: return cost;
156: }
157:
158: /* Return the register class of a scratch register needed to copy IN into
159: or out of a register in CLASS in MODE. If it can be done directly,
160: NO_REGS is returned. */
161:
162: enum reg_class
163: secondary_reload_class (class, mode, in)
164: enum reg_class class;
165: enum machine_mode mode;
166: rtx in;
167: {
168: int regno = true_regnum (in);
169:
170: if (regno >= FIRST_PSEUDO_REGISTER)
171: regno = -1;
172:
173: /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
174: into anything. */
175: if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
176: return NO_REGS;
177:
1.1.1.3 ! root 178: /* Constants, memory, and FP registers can go into FP registers. */
1.1 root 179: if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
180: return NO_REGS;
181:
1.1.1.3 ! root 182: #if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
! 183: so it's cleaner to use PREFERRED_RELOAD_CLASS
! 184: to make the right things happen. */
! 185: if (regno >= 16 && class == GEN_AND_MEM_REGS)
! 186: return NO_REGS;
! 187: #endif
! 188:
1.1 root 189: /* Otherwise, we need GENERAL_REGS. */
190: return GENERAL_REGS;
191: }
192: /* Generate the rtx that comes from an address expression in the md file */
193: /* The expression to be build is BASE[INDEX:SCALE]. To recognize this,
194: scale must be converted from an exponent (from ASHIFT) to a
1.1.1.2 root 195: multiplier (for MULT). */
1.1 root 196: rtx
197: gen_indexed_expr (base, index, scale)
198: rtx base, index, scale;
199: {
200: rtx addr;
201:
202: /* This generates an illegal addressing mode, if BASE is
203: fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */
204: if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
205: base = gen_rtx (MEM, SImode, base);
206: addr = gen_rtx (MULT, SImode, index,
207: gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
208: addr = gen_rtx (PLUS, SImode, base, addr);
209: return addr;
210: }
211:
212: /* Return 1 if OP is a valid operand of mode MODE. This
213: predicate rejects operands which do not have a mode
214: (such as CONST_INT which are VOIDmode). */
215: int
216: reg_or_mem_operand (op, mode)
217: register rtx op;
218: enum machine_mode mode;
219: {
220: return (GET_MODE (op) == mode
221: && (GET_CODE (op) == REG
222: || GET_CODE (op) == SUBREG
223: || GET_CODE (op) == MEM));
224: }
225:
226: /* Return the best assembler insn template
227: for moving operands[1] into operands[0] as a fullword. */
228:
229: static char *
230: singlemove_string (operands)
231: rtx *operands;
232: {
233: if (GET_CODE (operands[1]) == CONST_INT
234: && INTVAL (operands[1]) <= 7
235: && INTVAL (operands[1]) >= -8)
236: return "movqd %1,%0";
237: return "movd %1,%0";
238: }
239:
240: char *
241: output_move_double (operands)
242: rtx *operands;
243: {
244: enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
245: rtx latehalf[2];
246:
247: /* First classify both operands. */
248:
249: if (REG_P (operands[0]))
250: optype0 = REGOP;
251: else if (offsettable_memref_p (operands[0]))
252: optype0 = OFFSOP;
253: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
254: optype0 = POPOP;
255: else
256: optype0 = RNDOP;
257:
258: if (REG_P (operands[1]))
259: optype1 = REGOP;
260: else if (CONSTANT_ADDRESS_P (operands[1])
261: || GET_CODE (operands[1]) == CONST_DOUBLE)
262: optype1 = CNSTOP;
263: else if (offsettable_memref_p (operands[1]))
264: optype1 = OFFSOP;
265: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
266: optype1 = POPOP;
267: else
268: optype1 = RNDOP;
269:
270: /* Check for the cases that the operand constraints are not
271: supposed to allow to happen. Abort if we get one,
272: because generating code for these cases is painful. */
273:
274: if (optype0 == RNDOP || optype1 == RNDOP)
275: abort ();
276:
277: /* Ok, we can do one word at a time.
278: Normally we do the low-numbered word first,
279: but if either operand is autodecrementing then we
280: do the high-numbered word first.
281:
282: In either case, set up in LATEHALF the operands to use
283: for the high-numbered word and in some cases alter the
284: operands in OPERANDS to be suitable for the low-numbered word. */
285:
286: if (optype0 == REGOP)
287: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
288: else if (optype0 == OFFSOP)
289: latehalf[0] = adj_offsettable_operand (operands[0], 4);
290: else
291: latehalf[0] = operands[0];
292:
293: if (optype1 == REGOP)
294: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
295: else if (optype1 == OFFSOP)
296: latehalf[1] = adj_offsettable_operand (operands[1], 4);
297: else if (optype1 == CNSTOP)
298: {
299: if (CONSTANT_ADDRESS_P (operands[1]))
300: latehalf[1] = const0_rtx;
301: else if (GET_CODE (operands[1]) == CONST_DOUBLE)
302: split_double (operands[1], &operands[1], &latehalf[1]);
303: }
304: else
305: latehalf[1] = operands[1];
306:
307: /* If one or both operands autodecrementing,
308: do the two words, high-numbered first. */
309:
310: if (optype0 == POPOP || optype1 == POPOP)
311: {
312: output_asm_insn (singlemove_string (latehalf), latehalf);
313: return singlemove_string (operands);
314: }
315:
316: /* Not autodecrementing. Do the two words, low-numbered first. */
317:
318: output_asm_insn (singlemove_string (operands), operands);
319:
320: operands[0] = latehalf[0];
321: operands[1] = latehalf[1];
322: return singlemove_string (operands);
323: }
324:
325: int
326: check_reg (oper, reg)
327: rtx oper;
328: int reg;
329: {
330: register int i;
331:
332: if (oper == 0)
333: return 0;
334: switch (GET_CODE(oper))
335: {
336: case REG:
337: return (REGNO(oper) == reg) ? 1 : 0;
338: case MEM:
339: return check_reg(XEXP(oper, 0), reg);
340: case PLUS:
341: case MULT:
342: return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
343: }
344: return 0;
345: }
346:
347: /* PRINT_OPERAND is defined to call this function,
348: which is easier to debug than putting all the code in
349: a macro definition in ns32k.h. */
350:
351: void
352: print_operand (file, x, code)
353: FILE *file;
354: rtx x;
355: char code;
356: {
357: if (code == '$')
1.1.1.3 ! root 358: PUT_IMMEDIATE_PREFIX (file);
1.1 root 359: else if (code == '?')
1.1.1.3 ! root 360: PUT_EXTERNAL_PREFIX (file);
1.1 root 361: else if (GET_CODE (x) == REG)
362: fprintf (file, "%s", reg_names[REGNO (x)]);
363: else if (GET_CODE (x) == MEM)
1.1.1.2 root 364: {
365: rtx tmp = XEXP (x, 0);
1.1.1.3 ! root 366: #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
! 367: if (GET_CODE (tmp) != CONST_INT)
1.1.1.2 root 368: {
369: char *out = XSTR (tmp, 0);
370: if (out[0] == '*')
1.1.1.3 ! root 371: {
! 372: PUT_ABSOLUTE_PREFIX (file);
! 373: fprintf (file, "%s", &out[1]);
! 374: }
1.1.1.2 root 375: else
376: ASM_OUTPUT_LABELREF (file, out);
377: }
378: else
379: #endif
380: output_address (XEXP (x, 0));
381: }
1.1 root 382: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
1.1.1.2 root 383: {
384: if (GET_MODE (x) == DFmode)
385: {
386: union { double d; int i[2]; } u;
387: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
388: PUT_IMMEDIATE_PREFIX(file);
389: #ifdef SEQUENT_ASM
390: /* Sequent likes it's floating point constants as integers */
1.1.1.3 ! root 391: fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
1.1.1.2 root 392: #else
393: #ifdef ENCORE_ASM
394: fprintf (file, "0f%.20e", u.d);
395: #else
396: fprintf (file, "0d%.20e", u.d);
397: #endif
398: #endif
399: }
400: else
401: {
402: union { double d; int i[2]; } u;
403: u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
1.1.1.3 ! root 404: PUT_IMMEDIATE_PREFIX (file);
1.1.1.2 root 405: #ifdef SEQUENT_ASM
1.1.1.3 ! root 406: /* We have no way of winning if we can't get the bits
! 407: for a sequent floating point number. */
! 408: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
! 409: abort ();
! 410: #endif
1.1.1.2 root 411: {
412: union { float f; long l; } uu;
413: uu.f = u.d;
414: fprintf (file, "0Fx%08x", uu.l);
415: }
416: #else
417: fprintf (file, "0f%.20e", u.d);
418: #endif
419: }
420: }
1.1 root 421: else
422: {
1.1.1.3 ! root 423: #ifndef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
! 424: if (GET_CODE (x) == CONST_INT)
! 425: #endif
! 426: PUT_IMMEDIATE_PREFIX(file);
1.1 root 427: output_addr_const (file, x);
428: }
429: }
430:
431: /* PRINT_OPERAND_ADDRESS is defined to call this function,
432: which is easier to debug than putting all the code in
433: a macro definition in ns32k.h . */
434:
435: /* Completely rewritten to get this to work with Gas for PC532 Mach.
436: This function didn't work and I just wasn't able (nor very willing) to
437: figure out how it worked.
438: 90-11-25 Tatu Yl|nen <[email protected]> */
439:
440: print_operand_address (file, addr)
441: register FILE *file;
442: register rtx addr;
443: {
444: static char scales[] = { 'b', 'w', 'd', 0, 'q', };
445: rtx offset, base, indexexp, tmp;
446: int scale;
447:
448: if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
449: {
450: fprintf (file, "tos");
451: return;
452: }
453:
454: offset = NULL;
455: base = NULL;
456: indexexp = NULL;
457: while (addr != NULL)
458: {
459: if (GET_CODE (addr) == PLUS)
460: {
461: if (GET_CODE (XEXP (addr, 0)) == PLUS)
462: {
463: tmp = XEXP (addr, 1);
464: addr = XEXP (addr, 0);
465: }
466: else
467: {
468: tmp = XEXP (addr,0);
469: addr = XEXP (addr,1);
470: }
471: }
472: else
473: {
474: tmp = addr;
475: addr = NULL;
476: }
477: switch (GET_CODE (tmp))
478: {
479: case PLUS:
480: abort ();
481: case MEM:
482: if (base)
483: {
484: indexexp = base;
485: base = tmp;
486: }
487: else
488: base = tmp;
489: break;
490: case REG:
491: if (REGNO (tmp) < 8)
492: if (base)
493: {
494: indexexp = tmp;
495: }
496: else
497: base = tmp;
498: else
499: if (base)
500: {
501: indexexp = base;
502: base = tmp;
503: }
504: else
505: base = tmp;
506: break;
507: case MULT:
508: indexexp = tmp;
509: break;
510: case CONST:
511: case CONST_INT:
512: case SYMBOL_REF:
513: case LABEL_REF:
514: if (offset)
515: offset = gen_rtx (PLUS, SImode, tmp, offset);
516: else
517: offset = tmp;
518: break;
519: default:
520: abort ();
521: }
522: }
523: if (! offset)
524: offset = const0_rtx;
1.1.1.3 ! root 525:
! 526: #ifdef INDEX_RATHER_THAN_BASE
! 527: /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */
! 528: if (base && !indexexp && GET_CODE (base) == REG
! 529: && REG_OK_FOR_INDEX_P (REGNO (base))
! 530: {
! 531: indexexp = base;
! 532: base = 0;
! 533: }
! 534: #endif
! 535:
1.1 root 536: /* now, offset, base and indexexp are set */
537: if (! base)
538: {
1.1.1.2 root 539: #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
1.1.1.3 ! root 540: if (GET_CODE (offset) == CONST_INT)
! 541: /* if (! (GET_CODE (offset) == LABEL_REF
! 542: || GET_CODE (offset) == SYMBOL_REF)) */
1.1 root 543: #endif
544: PUT_ABSOLUTE_PREFIX (file);
545: }
546:
1.1.1.2 root 547: output_addr_const (file, offset);
1.1 root 548: if (base) /* base can be (REG ...) or (MEM ...) */
549: switch (GET_CODE (base))
550: {
551: /* now we must output base. Possible alternatives are:
552: (rN) (REG ...)
1.1.1.3 ! root 553: (sp) (REG ...)
1.1 root 554: (fp) (REG ...)
555: (pc) (REG ...) used for SYMBOL_REF and LABEL_REF, output
556: (disp(fp)) (MEM ...) just before possible [rX:y]
557: (disp(sp)) (MEM ...)
558: (disp(sb)) (MEM ...)
559: */
560: case REG:
561: fprintf (file, "(%s)", reg_names[REGNO (base)]);
562: break;
563: case MEM:
564: addr = XEXP(base,0);
565: base = NULL;
566: offset = NULL;
567: while (addr != NULL)
568: {
569: if (GET_CODE (addr) == PLUS)
570: {
571: if (GET_CODE (XEXP (addr, 0)) == PLUS)
572: {
573: tmp = XEXP (addr, 1);
574: addr = XEXP (addr, 0);
575: }
576: else
577: {
578: tmp = XEXP (addr, 0);
579: addr = XEXP (addr, 1);
580: }
581: }
582: else
583: {
584: tmp = addr;
585: addr = NULL;
586: }
587: switch (GET_CODE (tmp))
588: {
589: case REG:
590: base = tmp;
591: break;
592: case CONST:
593: case CONST_INT:
594: case SYMBOL_REF:
595: case LABEL_REF:
596: if (offset)
597: offset = gen_rtx (PLUS, SImode, tmp, offset);
598: else
599: offset = tmp;
600: break;
601: default:
602: abort ();
603: }
604: }
605: if (! offset)
606: offset = const0_rtx;
607: fprintf (file, "(");
608: output_addr_const (file, offset);
609: if (base)
610: fprintf (file, "(%s)", reg_names[REGNO (base)]);
1.1.1.2 root 611: #ifdef BASE_REG_NEEDED
1.1 root 612: else if (TARGET_SB)
613: fprintf (file, "(sb)");
614: else
615: abort ();
1.1.1.2 root 616: #endif
1.1 root 617: fprintf (file, ")");
618: break;
619:
620: default:
621: abort ();
622: }
623: #ifdef PC_RELATIVE
624: else /* no base */
625: if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
626: fprintf (file, "(pc)");
627: #endif
628: #ifdef BASE_REG_NEEDED /* this is defined if the assembler always
629: needs a base register */
630: else if (TARGET_SB)
631: fprintf (file, "(sb)");
632: else
633: abort ();
634: #endif
635: /* now print index if we have one */
636: if (indexexp)
637: {
638: if (GET_CODE (indexexp) == MULT)
639: {
640: scale = INTVAL (XEXP (indexexp, 1)) >> 1;
641: indexexp = XEXP (indexexp, 0);
642: }
643: else
644: scale = 0;
645: if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
646: abort ();
647:
1.1.1.3 ! root 648: #ifdef UTEK_ASM
! 649: fprintf (file, "[%c`%s]",
! 650: scales[scale],
! 651: reg_names[REGNO (indexexp)]);
! 652: #else
1.1 root 653: fprintf (file, "[%s:%c]",
654: reg_names[REGNO (indexexp)],
655: scales[scale]);
1.1.1.3 ! root 656: #endif
1.1 root 657: }
658: }
659:
660: /* National 32032 shifting is so bad that we can get
661: better performance in many common cases by using other
662: techniques. */
663: char *
664: output_shift_insn (operands)
665: rtx *operands;
666: {
667: if (GET_CODE (operands[2]) == CONST_INT
668: && INTVAL (operands[2]) > 0
669: && INTVAL (operands[2]) <= 3)
670: if (GET_CODE (operands[0]) == REG)
671: {
672: if (GET_CODE (operands[1]) == REG)
673: {
674: if (REGNO (operands[0]) == REGNO (operands[1]))
675: {
676: if (operands[2] == const1_rtx)
677: return "addd %0,%0";
678: else if (INTVAL (operands[2]) == 2)
679: return "addd %0,%0\n\taddd %0,%0";
680: }
681: if (operands[2] == const1_rtx)
682: return "movd %1,%0\n\taddd %0,%0";
683:
684: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
685: return "addr %a1,%0";
686: }
687: if (operands[2] == const1_rtx)
688: return "movd %1,%0\n\taddd %0,%0";
689: }
690: else if (GET_CODE (operands[1]) == REG)
691: {
692: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
693: return "addr %a1,%0";
694: }
695: else if (INTVAL (operands[2]) == 1
696: && GET_CODE (operands[1]) == MEM
697: && rtx_equal_p (operands [0], operands[1]))
698: {
699: rtx temp = XEXP (operands[1], 0);
700:
701: if (GET_CODE (temp) == REG
702: || (GET_CODE (temp) == PLUS
703: && GET_CODE (XEXP (temp, 0)) == REG
704: && GET_CODE (XEXP (temp, 1)) == CONST_INT))
705: return "addd %0,%0";
706: }
707: else return "ashd %2,%0";
708: return "ashd %2,%0";
709: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.