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