|
|
1.1 root 1: /* Subroutines used for code generation on ROMP.
2: Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3: Contributed by Richard Kenner ([email protected])
4:
5: This file is part of GNU CC.
6:
7: GNU CC is free software; you can redistribute it and/or modify
8: it under the terms of the GNU General Public License as published by
9: the Free Software Foundation; either version 2, or (at your option)
10: any later version.
11:
12: GNU CC is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with GNU CC; see the file COPYING. If not, write to
19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20:
21:
22: #include <stdio.h>
23: #include "config.h"
24: #include "rtl.h"
25: #include "regs.h"
26: #include "hard-reg-set.h"
27: #include "real.h"
28: #include "insn-config.h"
29: #include "conditions.h"
30: #include "insn-flags.h"
31: #include "output.h"
32: #include "insn-attr.h"
33: #include "flags.h"
34: #include "recog.h"
35: #include "expr.h"
36: #include "obstack.h"
37: #include "tree.h"
38:
39: #define min(A,B) ((A) < (B) ? (A) : (B))
40: #define max(A,B) ((A) > (B) ? (A) : (B))
41:
42: static int unsigned_comparisons_p ();
43: static void output_loadsave_fpregs ();
44: static void output_fpops ();
45: static void init_fpops ();
46:
47: /* Return 1 if the insn using CC0 set by INSN does not contain
48: any unsigned tests applied to the condition codes.
49:
50: Based on `next_insn_tests_no_inequality' in recog.c. */
51:
52: int
53: next_insn_tests_no_unsigned (insn)
54: rtx insn;
55: {
56: register rtx next = next_cc0_user (insn);
57:
58: if (next == 0)
59: {
60: if (find_reg_note (insn, REG_UNUSED, cc0_rtx))
61: return 1;
62: else
63: abort ();
64: }
65:
66: return ((GET_CODE (next) == JUMP_INSN
67: || GET_CODE (next) == INSN
68: || GET_CODE (next) == CALL_INSN)
69: && ! unsigned_comparisons_p (PATTERN (next)));
70: }
71:
72: static int
73: unsigned_comparisons_p (x)
74: rtx x;
75: {
76: register char *fmt;
77: register int len, i;
78: register enum rtx_code code = GET_CODE (x);
79:
80: switch (code)
81: {
82: case REG:
83: case PC:
84: case CC0:
85: case CONST_INT:
86: case CONST_DOUBLE:
87: case CONST:
88: case LABEL_REF:
89: case SYMBOL_REF:
90: return 0;
91:
92: case LTU:
93: case GTU:
94: case LEU:
95: case GEU:
96: return (XEXP (x, 0) == cc0_rtx || XEXP (x, 1) == cc0_rtx);
97: }
98:
99: len = GET_RTX_LENGTH (code);
100: fmt = GET_RTX_FORMAT (code);
101:
102: for (i = 0; i < len; i++)
103: {
104: if (fmt[i] == 'e')
105: {
106: if (unsigned_comparisons_p (XEXP (x, i)))
107: return 1;
108: }
109: else if (fmt[i] == 'E')
110: {
111: register int j;
112: for (j = XVECLEN (x, i) - 1; j >= 0; j--)
113: if (unsigned_comparisons_p (XVECEXP (x, i, j)))
114: return 1;
115: }
116: }
117:
118: return 0;
119: }
120:
121: /* Update the condition code from the insn. Look mostly at the first
122: byte of the machine-specific insn description information.
123:
124: cc_state.value[12] refer to two possible values that might correspond
125: to the CC. We only store register values. */
126:
127: update_cc (body, insn)
128: rtx body;
129: rtx insn;
130: {
131: switch (get_attr_cc (insn))
132: {
133: case CC_NONE:
134: /* Insn does not affect the CC at all. */
135: break;
136:
137: case CC_CHANGE0:
138: /* Insn doesn't affect the CC but does modify operand[0], known to be
139: a register. */
140: if (cc_status.value1 != 0
141: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
142: cc_status.value1 = 0;
143:
144: if (cc_status.value2 != 0
145: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
146: cc_status.value2 = 0;
147:
148: break;
149:
150: case CC_COPY1TO0:
151: /* Insn copies operand[1] to operand[0], both registers, but doesn't
152: affect the CC. */
153: if (cc_status.value1 != 0
154: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
155: cc_status.value1 = 0;
156:
157: if (cc_status.value2 != 0
158: && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
159: cc_status.value2 = 0;
160:
161: if (cc_status.value1 != 0
162: && rtx_equal_p (cc_status.value1, recog_operand[1]))
163: cc_status.value2 = recog_operand[0];
164:
165: if (cc_status.value2 != 0
166: && rtx_equal_p (cc_status.value2, recog_operand[1]))
167: cc_status.value1 = recog_operand[0];
168:
169: break;
170:
171: case CC_CLOBBER:
172: /* Insn clobbers CC. */
173: CC_STATUS_INIT;
174: break;
175:
176: case CC_SETS:
177: /* Insn sets CC to recog_operand[0], but overflow is impossible. */
178: CC_STATUS_INIT;
179: cc_status.flags |= CC_NO_OVERFLOW;
180: cc_status.value1 = recog_operand[0];
181: break;
182:
183: case CC_COMPARE:
184: /* Insn is a compare which sets the CC fully. Update CC_STATUS for this
185: compare and mark whether the test will be signed or unsigned. */
186: {
187: register rtx p = PATTERN (insn);
188:
189: CC_STATUS_INIT;
190:
191: if (GET_CODE (p) == PARALLEL)
192: p = XVECEXP (p, 0, 0);
193: cc_status.value1 = SET_SRC (p);
194:
195: if (GET_CODE (SET_SRC (p)) == REG)
196: cc_status.flags |= CC_NO_OVERFLOW;
197: if (! next_insn_tests_no_unsigned (insn))
198: cc_status.flags |= CC_UNSIGNED;
199: }
200: break;
201:
202: case CC_TBIT:
203: /* Insn sets T bit if result is non-zero. Next insn must be branch. */
204: CC_STATUS_INIT;
205: cc_status.flags = CC_IN_TB | CC_NOT_NEGATIVE;
206: break;
207:
208: default:
209: abort ();
210: }
211: }
212:
213: /* Return 1 if a previous compare needs to be re-issued. This will happen
214: if two compares tested the same objects, but one was signed and the
215: other unsigned. OP is the comparison operation being performed. */
216:
217: int
218: restore_compare_p (op)
219: rtx op;
220: {
221: enum rtx_code code = GET_CODE (op);
222:
223: return (((code == GEU || code == LEU || code == GTU || code == LTU)
224: && ! (cc_status.flags & CC_UNSIGNED))
225: || ((code == GE || code == LE || code == GT || code == LT)
226: && (cc_status.flags & CC_UNSIGNED)));
227: }
228:
229: /* Generate the (long) string corresponding to an inline multiply insn.
230: Note that `r10' does not refer to the register r10, but rather to the
231: SCR used as the MQ. */
232: char *
233: output_in_line_mul ()
234: {
235: static char insns[200];
236: int i;
237:
238: strcpy (insns, "s %0,%0\n");
239: strcat (insns, "\tmts r10,%1\n");
240: for (i = 0; i < 16; i++)
241: strcat (insns, "\tm %0,%2\n");
242: strcat (insns, "\tmfs r10,%0");
243:
244: return insns;
245: }
246:
247: /* Returns 1 if OP is a memory reference with an offset from a register within
248: the range specified. The offset must also be a multiple of the size of the
249: mode. */
250:
251: static int
252: memory_offset_in_range_p (op, mode, low, high)
253: register rtx op;
254: enum machine_mode mode;
255: int low, high;
256: {
257: int offset = 0;
258:
259: if (! memory_operand (op, mode))
260: return 0;
261:
262: while (GET_CODE (op) == SUBREG)
263: {
264: offset += SUBREG_WORD (op) * UNITS_PER_WORD;
265: #if BYTES_BIG_ENDIAN
266: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
267: - min (UNITS_PER_WORD,
268: GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))));
269: #endif
270: op = SUBREG_REG (op);
271: }
272:
273: /* We must now have either (mem (reg (x)), (mem (plus (reg (x)) (c))),
274: or a constant pool address. */
275: if (GET_CODE (op) != MEM)
276: abort ();
277:
278: /* Now use the actual mode and get the address. */
279: mode = GET_MODE (op);
280: op = XEXP (op, 0);
281: if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))
282: offset = get_pool_offset (op) + 12;
283: else if (GET_CODE (op) == PLUS)
284: {
285: if (GET_CODE (XEXP (op, 1)) != CONST_INT
286: || ! register_operand (XEXP (op, 0), Pmode))
287: return 0;
288:
289: offset += INTVAL (XEXP (op, 1));
290: }
291:
292: else if (! register_operand (op, Pmode))
293: return 0;
294:
295: return (offset >= low && offset <= high
296: && (offset % GET_MODE_SIZE (mode) == 0));
297: }
298:
299: /* Return 1 if OP is a valid operand for a memory reference insn that can
300: only reference indirect through a register. */
301:
302: int
303: zero_memory_operand (op, mode)
304: rtx op;
305: enum machine_mode mode;
306: {
307: return memory_offset_in_range_p (op, mode, 0, 0);
308: }
309:
310: /* Return 1 if OP is a valid operand for a `short' memory reference insn. */
311:
312: int
313: short_memory_operand (op, mode)
314: rtx op;
315: enum machine_mode mode;
316: {
317: if (mode == VOIDmode)
318: mode = GET_MODE (op);
319:
320: return memory_offset_in_range_p (op, mode, 0,
321: 15 * min (UNITS_PER_WORD,
322: GET_MODE_SIZE (mode)));
323: }
324:
325: /* Returns 1 if OP is a memory reference involving a symbolic constant
326: that is not in the constant pool. */
327:
328: int
329: symbolic_memory_operand (op, mode)
330: register rtx op;
331: enum machine_mode mode;
332: {
333: if (! memory_operand (op, mode))
334: return 0;
335:
336: while (GET_CODE (op) == SUBREG)
337: op = SUBREG_REG (op);
338:
339: if (GET_CODE (op) != MEM)
340: abort ();
341:
342: op = XEXP (op, 0);
343: if (constant_pool_address_operand (op, VOIDmode))
344: return 0;
345: else
346: return romp_symbolic_operand (op, Pmode)
347: || (GET_CODE (op) == PLUS && register_operand (XEXP (op, 0), Pmode)
348: && romp_symbolic_operand (XEXP (op, 1), Pmode));
349: }
350:
351:
352: /* Returns 1 if OP is a constant pool reference to the current function. */
353:
354: int
355: current_function_operand (op, mode)
356: rtx op;
357: enum machine_mode mode;
358: {
359: if (GET_CODE (op) != MEM || GET_CODE (XEXP (op, 0)) != SYMBOL_REF
360: || ! CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
361: return 0;
362:
363: op = get_pool_constant (XEXP (op, 0));
364: return (GET_CODE (op) == SYMBOL_REF
365: && ! strcmp (current_function_name, XSTR (op, 0)));
366: }
367:
368: /* Return non-zero if this function is known to have a null epilogue. */
369:
370: int
371: null_epilogue ()
372: {
373: return (reload_completed
374: && first_reg_to_save () == 16
375: && ! romp_pushes_stack ());
376: }
377:
378: /* Returns 1 if OP is the address of a location in the constant pool. */
379:
380: int
381: constant_pool_address_operand (op, mode)
382: rtx op;
383: enum machine_mode mode;
384: {
385: return ((GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op))
386: || (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == PLUS
387: && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
388: && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
389: && CONSTANT_POOL_ADDRESS_P (XEXP (XEXP (op, 0), 0))));
390: }
391:
392: /* Returns 1 if OP is either a symbol reference or a sum of a symbol
393: reference and a constant. */
394:
395: int
396: romp_symbolic_operand (op, mode)
397: register rtx op;
398: enum machine_mode mode;
399: {
400: switch (GET_CODE (op))
401: {
402: case SYMBOL_REF:
403: case LABEL_REF:
404: return ! op->integrated;
405:
406: case CONST:
407: op = XEXP (op, 0);
408: return (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
409: || GET_CODE (XEXP (op, 0)) == LABEL_REF)
410: && GET_CODE (XEXP (op, 1)) == CONST_INT;
411:
412: default:
413: return 0;
414: }
415: }
416:
417: /* Returns 1 if OP is a valid constant for the ROMP. */
418:
419: int
420: constant_operand (op, mode)
421: register rtx op;
422: enum machine_mode mode;
423: {
424: switch (GET_CODE (op))
425: {
426: case LABEL_REF:
427: case SYMBOL_REF:
428: case PLUS:
429: case CONST:
430: return romp_symbolic_operand (op,mode);
431:
432: case CONST_INT:
433: return (unsigned int) (INTVAL (op) + 0x8000) < 0x10000
434: || (INTVAL (op) & 0xffff) == 0 || (INTVAL (op) & 0xffff0000) == 0;
435:
436: default:
437: return 0;
438: }
439: }
440:
441: /* Returns 1 if OP is either a constant integer valid for the ROMP or a
442: register. If a register, it must be in the proper mode unless MODE is
443: VOIDmode. */
444:
445: int
446: reg_or_cint_operand (op, mode)
447: register rtx op;
448: enum machine_mode mode;
449: {
450: if (GET_CODE (op) == CONST_INT)
451: return constant_operand (op, mode);
452:
453: return register_operand (op, mode);
454: }
455:
456: /* Return 1 is the operand is either a register or ANY constant integer. */
457:
458: int
459: reg_or_any_cint_operand (op, mode)
460: register rtx op;
461: enum machine_mode mode;
462: {
463: return GET_CODE (op) == CONST_INT || register_operand (op, mode);
464: }
465:
466: /* Return 1 if the operand is either a register or a valid D-type operand. */
467:
468: int
469: reg_or_D_operand (op, mode)
470: register rtx op;
471: enum machine_mode mode;
472: {
473: if (GET_CODE (op) == CONST_INT)
474: return (unsigned) (INTVAL (op) + 0x8000) < 0x10000;
475:
476: return register_operand (op, mode);
477: }
478:
479: /* Return 1 if the operand is either a register or an item that can be
480: used as the operand of an SI add insn. */
481:
482: int
483: reg_or_add_operand (op, mode)
484: register rtx op;
485: enum machine_mode mode;
486: {
487: return reg_or_D_operand (op, mode) || romp_symbolic_operand (op, mode)
488: || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
489: }
490:
491: /* Return 1 if the operand is either a register or an item that can be
492: used as the operand of a ROMP logical AND insn. */
493:
494: int
495: reg_or_and_operand (op, mode)
496: register rtx op;
497: enum machine_mode mode;
498: {
499: if (reg_or_cint_operand (op, mode))
500: return 1;
501:
502: if (GET_CODE (op) != CONST_INT)
503: return 0;
504:
505: return (INTVAL (op) & 0xffff) == 0xffff
506: || (INTVAL (op) & 0xffff0000) == 0xffff0000;
507: }
508:
509: /* Return 1 if the operand is a register or memory operand. */
510:
511: int
512: reg_or_mem_operand (op, mode)
513: register rtx op;
514: register enum machine_mode mode;
515: {
516: return register_operand (op, mode) || memory_operand (op, mode);
517: }
518:
519: /* Return 1 if the operand is either a register or a memory operand that is
520: not symbolic. */
521:
522: int
523: reg_or_nonsymb_mem_operand (op, mode)
524: register rtx op;
525: enum machine_mode mode;
526: {
527: if (register_operand (op, mode))
528: return 1;
529:
530: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
531: return 1;
532:
533: return 0;
534: }
535:
536: /* Return 1 if this operand is valid for the ROMP. This is any operand except
537: certain constant integers. */
538:
539: int
540: romp_operand (op, mode)
541: register rtx op;
542: enum machine_mode mode;
543: {
544: if (GET_CODE (op) == CONST_INT)
545: return constant_operand (op, mode);
546:
547: return general_operand (op, mode);
548: }
549:
550: /* Return 1 if the operand is (reg:mode 0). */
551:
552: int
553: reg_0_operand (op, mode)
554: rtx op;
555: enum machine_mode mode;
556: {
557: return ((mode == VOIDmode || mode == GET_MODE (op))
558: && GET_CODE (op) == REG && REGNO (op) == 0);
559: }
560:
561: /* Return 1 if the operand is (reg:mode 15). */
562:
563: int
564: reg_15_operand (op, mode)
565: rtx op;
566: enum machine_mode mode;
567: {
568: return ((mode == VOIDmode || mode == GET_MODE (op))
569: && GET_CODE (op) == REG && REGNO (op) == 15);
570: }
571:
572: /* Return 1 if this is a binary floating-point operation. */
573:
574: int
575: float_binary (op, mode)
576: register rtx op;
577: enum machine_mode mode;
578: {
579: if (mode != VOIDmode && mode != GET_MODE (op))
580: return 0;
581:
582: if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode)
583: return 0;
584:
585: switch (GET_CODE (op))
586: {
587: case PLUS:
588: case MINUS:
589: case MULT:
590: case DIV:
591: return GET_MODE (XEXP (op, 0)) == GET_MODE (op)
592: && GET_MODE (XEXP (op, 1)) == GET_MODE (op);
593:
594: default:
595: return 0;
596: }
597: }
598:
599: /* Return 1 if this is a unary floating-point operation. */
600:
601: int
602: float_unary (op, mode)
603: register rtx op;
604: enum machine_mode mode;
605: {
606: if (mode != VOIDmode && mode != GET_MODE (op))
607: return 0;
608:
609: if (GET_MODE (op) != SFmode && GET_MODE (op) != DFmode)
610: return 0;
611:
612: return (GET_CODE (op) == NEG || GET_CODE (op) == ABS)
613: && GET_MODE (XEXP (op, 0)) == GET_MODE (op);
614: }
615:
616: /* Return 1 if this is a valid floating-point conversion that can be done
617: as part of an operation by the RT floating-point routines. */
618:
619: int
620: float_conversion (op, mode)
621: register rtx op;
622: enum machine_mode mode;
623: {
624: if (mode != VOIDmode && mode != GET_MODE (op))
625: return 0;
626:
627: switch (GET_CODE (op))
628: {
629: case FLOAT_TRUNCATE:
630: return GET_MODE (op) == SFmode && GET_MODE (XEXP (op, 0)) == DFmode;
631:
632: case FLOAT_EXTEND:
633: return GET_MODE (op) == DFmode && GET_MODE (XEXP (op, 0)) == SFmode;
634:
635: case FLOAT:
636: return ((GET_MODE (XEXP (op, 0)) == SImode
637: || GET_CODE (XEXP (op, 0)) == CONST_INT)
638: && (GET_MODE (op) == SFmode || GET_MODE (op) == DFmode));
639:
640: case FIX:
641: return ((GET_MODE (op) == SImode
642: || GET_CODE (XEXP (op, 0)) == CONST_INT)
643: && (GET_MODE (XEXP (op, 0)) == SFmode
644: || GET_MODE (XEXP (op, 0)) == DFmode));
645:
646: default:
647: return 0;
648: }
649: }
650:
651: /* Print an operand. Recognize special options, documented below. */
652:
653: void
654: print_operand (file, x, code)
655: FILE *file;
656: rtx x;
657: char code;
658: {
659: int i;
660:
661: switch (code)
662: {
663: case 'B':
664: /* Byte number (const/8) */
665: if (GET_CODE (x) != CONST_INT)
666: output_operand_lossage ("invalid %%B value");
667:
668: fprintf (file, "%d", INTVAL (x) / 8);
669: break;
670:
671: case 'L':
672: /* Low order 16 bits of constant. */
673: if (GET_CODE (x) != CONST_INT)
674: output_operand_lossage ("invalid %%L value");
675:
676: fprintf (file, "%d", INTVAL (x) & 0xffff);
677: break;
678:
679: case 's':
680: /* Null or "16" depending on whether the constant is greater than 16. */
681: if (GET_CODE (x) != CONST_INT)
682: output_operand_lossage ("invalid %%s value");
683:
684: if (INTVAL (x) >= 16)
685: fprintf (file, "16");
686:
687: break;
688:
689: case 'S':
690: /* For shifts: 's' will have given the half. Just give the amount
691: within 16. */
692: if (GET_CODE (x) != CONST_INT)
693: output_operand_lossage ("invalid %%S value");
694:
695: fprintf (file, "%d", INTVAL (x) & 15);
696: break;
697:
698: case 'b':
699: /* The number of a single bit set or cleared, mod 16. Note that the ROMP
700: numbers bits with the high-order bit 31. */
701: if (GET_CODE (x) != CONST_INT)
702: output_operand_lossage ("invalid %%b value");
703:
704: if ((i = exact_log2 (INTVAL (x))) >= 0)
705: fprintf (file, "%d", (31 - i) % 16);
706: else if ((i = exact_log2 (~ INTVAL (x))) >= 0)
707: fprintf (file, "%d", (31 - i) % 16);
708: else
709: output_operand_lossage ("invalid %%b value");
710:
711: break;
712:
713: case 'h':
714: /* "l" or "u" depending on which half of the constant is zero. */
715: if (GET_CODE (x) != CONST_INT)
716: output_operand_lossage ("invalid %%h value");
717:
718: if ((INTVAL (x) & 0xffff0000) == 0)
719: fprintf (file, "l");
720: else if ((INTVAL (x) & 0xffff) == 0)
721: fprintf (file, "u");
722: else
723: output_operand_lossage ("invalid %%h value");
724:
725: break;
726:
727: case 'H':
728: /* Upper or lower half, depending on which half is zero. */
729: if (GET_CODE (x) != CONST_INT)
730: output_operand_lossage ("invalid %%H value");
731:
732: if ((INTVAL (x) & 0xffff0000) == 0)
733: fprintf (file, "%d", INTVAL (x) & 0xffff);
734: else if ((INTVAL (x) & 0xffff) == 0)
735: fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff);
736: else
737: output_operand_lossage ("invalid %%H value");
738:
739: break;
740:
741: case 'z':
742: /* Write two characters:
743: 'lo' if the high order part is all ones
744: 'lz' if the high order part is all zeros
745: 'uo' if the low order part is all ones
746: 'uz' if the low order part is all zeros
747: */
748: if (GET_CODE (x) != CONST_INT)
749: output_operand_lossage ("invalid %%z value");
750:
751: if ((INTVAL (x) & 0xffff0000) == 0)
752: fprintf (file, "lz");
753: else if ((INTVAL (x) & 0xffff0000) == 0xffff0000)
754: fprintf (file, "lo");
755: else if ((INTVAL (x) & 0xffff) == 0)
756: fprintf (file, "uz");
757: else if ((INTVAL (x) & 0xffff) == 0xffff)
758: fprintf (file, "uo");
759: else
760: output_operand_lossage ("invalid %%z value");
761:
762: break;
763:
764: case 'Z':
765: /* Upper or lower half, depending on which is non-zero or not
766: all ones. Must be consistent with 'z' above. */
767: if (GET_CODE (x) != CONST_INT)
768: output_operand_lossage ("invalid %%Z value");
769:
770: if ((INTVAL (x) & 0xffff0000) == 0
771: || (INTVAL (x) & 0xffff0000) == 0xffff0000)
772: fprintf (file, "%d", INTVAL (x) & 0xffff);
773: else if ((INTVAL (x) & 0xffff) == 0 || (INTVAL (x) & 0xffff) == 0xffff)
774: fprintf (file, "%d", (INTVAL (x) >> 16) & 0xffff);
775: else
776: output_operand_lossage ("invalid %%Z value");
777:
778: break;
779:
780: case 'k':
781: /* Same as 'z', except the trailing 'o' or 'z' is not written. */
782: if (GET_CODE (x) != CONST_INT)
783: output_operand_lossage ("invalid %%k value");
784:
785: if ((INTVAL (x) & 0xffff0000) == 0
786: || (INTVAL (x) & 0xffff0000) == 0xffff0000)
787: fprintf (file, "l");
788: else if ((INTVAL (x) & 0xffff) == 0
789: || (INTVAL (x) & 0xffff) == 0xffff)
790: fprintf (file, "u");
791: else
792: output_operand_lossage ("invalid %%k value");
793:
794: break;
795:
796: case 't':
797: /* Similar to 's', except that we write 'h' or 'u'. */
798: if (GET_CODE (x) != CONST_INT)
799: output_operand_lossage ("invalid %%k value");
800:
801: if (INTVAL (x) < 16)
802: fprintf (file, "u");
803: else
804: fprintf (file, "l");
805: break;
806:
807: case 'M':
808: /* For memory operations, write 's' if the operand is a short
809: memory operand. */
810: if (short_memory_operand (x, VOIDmode))
811: fprintf (file, "s");
812: break;
813:
814: case 'N':
815: /* Like 'M', but check for zero memory offset. */
816: if (zero_memory_operand (x, VOIDmode))
817: fprintf (file, "s");
818: break;
819:
820: case 'O':
821: /* Write low-order part of DImode or DFmode. Supported for MEM
822: and REG only. */
823: if (GET_CODE (x) == REG)
824: fprintf (file, "%s", reg_names[REGNO (x) + 1]);
825: else if (GET_CODE (x) == MEM)
826: print_operand (file, gen_rtx (MEM, GET_MODE (x),
827: plus_constant (XEXP (x, 0), 4)), 0);
828: else
829: abort ();
830: break;
831:
832: case 'C':
833: /* Offset in constant pool for constant pool address. */
834: if (! constant_pool_address_operand (x, VOIDmode))
835: abort ();
836: if (GET_CODE (x) == SYMBOL_REF)
837: fprintf (file, "%d", get_pool_offset (x) + 12);
838: else
839: /* Must be (const (plus (symbol_ref) (const_int))) */
840: fprintf (file, "%d",
841: (get_pool_offset (XEXP (XEXP (x, 0), 0)) + 12
842: + INTVAL (XEXP (XEXP (x, 0), 1))));
843: break;
844:
845: case 'j':
846: /* Branch opcode. Check for condition in test bit for eq/ne. */
847: switch (GET_CODE (x))
848: {
849: case EQ:
850: if (cc_status.flags & CC_IN_TB)
851: fprintf (file, "ntb");
852: else
853: fprintf (file, "eq");
854: break;
855:
856: case NE:
857: if (cc_status.flags & CC_IN_TB)
858: fprintf (file, "tb");
859: else
860: fprintf (file, "ne");
861: break;
862:
863: case GT:
864: case GTU:
865: fprintf (file, "h");
866: break;
867:
868: case LT:
869: case LTU:
870: fprintf (file, "l");
871: break;
872:
873: case GE:
874: case GEU:
875: fprintf (file, "he");
876: break;
877:
878: case LE:
879: case LEU:
880: fprintf (file, "le");
881: break;
882:
883: default:
884: output_operand_lossage ("invalid %%j value");
885: }
886: break;
887:
888: case 'J':
889: /* Reversed branch opcode. */
890: switch (GET_CODE (x))
891: {
892: case EQ:
893: if (cc_status.flags & CC_IN_TB)
894: fprintf (file, "tb");
895: else
896: fprintf (file, "ne");
897: break;
898:
899: case NE:
900: if (cc_status.flags & CC_IN_TB)
901: fprintf (file, "ntb");
902: else
903: fprintf (file, "eq");
904: break;
905:
906: case GT:
907: case GTU:
908: fprintf (file, "le");
909: break;
910:
911: case LT:
912: case LTU:
913: fprintf (file, "he");
914: break;
915:
916: case GE:
917: case GEU:
918: fprintf (file, "l");
919: break;
920:
921: case LE:
922: case LEU:
923: fprintf (file, "h");
924: break;
925:
926: default:
927: output_operand_lossage ("invalid %%j value");
928: }
929: break;
930:
931: case '.':
932: /* Output nothing. Used as delimiter in, e.g., "mc%B1%.3 " */
933: break;
934:
935: case '#':
936: /* Output 'x' if this insn has a delay slot, else nothing. */
937: if (dbr_sequence_length ())
938: fprintf (file, "x");
939: break;
940:
941: case 0:
942: if (GET_CODE (x) == REG)
943: fprintf (file, "%s", reg_names[REGNO (x)]);
944: else if (GET_CODE (x) == MEM)
945: {
946: if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
947: && current_function_operand (x, Pmode))
948: fprintf (file, "r14");
949: else
950: output_address (XEXP (x, 0));
951: }
952: else
953: output_addr_const (file, x);
954: break;
955:
956: default:
957: output_operand_lossage ("invalid %%xn code");
958: }
959: }
960:
961: /* This page contains routines that are used to determine what the function
962: prologue and epilogue code will do and write them out. */
963:
964: /* Return the first register that is required to be saved. 16 if none. */
965:
966: int
967: first_reg_to_save()
968: {
969: int first_reg;
970:
971: /* Find lowest numbered live register. */
972: for (first_reg = 6; first_reg <= 15; first_reg++)
973: if (regs_ever_live[first_reg])
974: break;
975:
976: /* If we think that we do not have to save r14, see if it will be used
977: to be sure. */
978: if (first_reg > 14 && romp_using_r14 ())
979: first_reg = 14;
980:
981: return first_reg;
982: }
983:
984: /* Compute the size of the save area in the stack, including the space for
985: the first four incoming arguments. */
986:
987: int
988: romp_sa_size ()
989: {
990: int size;
991: int i;
992:
993: /* We have the 4 words corresponding to the arguments passed in registers,
994: 4 reserved words, space for static chain, general register save area,
995: and floating-point save area. */
996: size = 4 + 4 + 1 + (16 - first_reg_to_save ());
997:
998: /* The documentation says we have to leave 18 words in the save area if
999: any floating-point registers at all are saved, not the three words
1000: per register you might otherwise expect. */
1001: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++)
1002: if (regs_ever_live[i + 17])
1003: {
1004: size += 18;
1005: break;
1006: }
1007:
1008: return size * 4;
1009: }
1010:
1011: /* Return non-zero if this function makes calls or has fp operations
1012: (which are really calls). */
1013:
1014: int
1015: romp_makes_calls ()
1016: {
1017: rtx insn;
1018:
1019: for (insn = get_insns (); insn; insn = next_insn (insn))
1020: {
1021: if (GET_CODE (insn) == CALL_INSN)
1022: return 1;
1023: else if (GET_CODE (insn) == INSN)
1024: {
1025: rtx body = PATTERN (insn);
1026:
1027: if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER
1028: && GET_CODE (body) != ADDR_VEC
1029: && GET_CODE (body) != ADDR_DIFF_VEC
1030: && get_attr_type (insn) == TYPE_FP)
1031: return 1;
1032: }
1033: }
1034:
1035: return 0;
1036: }
1037:
1038: /* Return non-zero if this function will use r14 as a pointer to its
1039: constant pool. */
1040:
1041: int
1042: romp_using_r14 ()
1043: {
1044: /* If we are debugging, profiling, have a non-empty constant pool, or
1045: call a function, we need r14. */
1046: return (write_symbols != NO_DEBUG || profile_flag || get_pool_size () != 0
1047: || romp_makes_calls ());
1048: }
1049:
1050: /* Return non-zero if this function needs to push space on the stack. */
1051:
1052: int
1053: romp_pushes_stack ()
1054: {
1055: /* We need to push the stack if a frame pointer is needed (because the
1056: stack might be dynamically adjusted), if we are debugging, if the
1057: total required size is more than 100 bytes, or if we make calls. */
1058:
1059: return (frame_pointer_needed || write_symbols != NO_DEBUG
1060: || (romp_sa_size () + get_frame_size ()) > 100
1061: || romp_makes_calls ());
1062: }
1063:
1064: /* Write function prologue.
1065:
1066: We compute the size of the fixed area required as follows:
1067:
1068: We always allocate 4 words for incoming arguments, 4 word reserved, 1
1069: word for static link, as many words as required for general register
1070: save area, plus 2 words for each FP reg 2-7 that must be saved. */
1071:
1072: void
1073: output_prolog (file, size)
1074: FILE *file;
1075: int size;
1076: {
1077: int first_reg;
1078: int reg_save_offset;
1079: rtx insn;
1080: int fp_save = size + current_function_outgoing_args_size;
1081:
1082: init_fpops ();
1083:
1084: /* Add in fixed size plus output argument area. */
1085: size += romp_sa_size () + current_function_outgoing_args_size;
1086:
1087: /* Compute first register to save and perform the save operation if anything
1088: needs to be saved. */
1089: first_reg = first_reg_to_save();
1090: reg_save_offset = - (4 + 4 + 1 + (16 - first_reg)) * 4;
1091: if (first_reg == 15)
1092: fprintf (file, "\tst r15,%d(r1)\n", reg_save_offset);
1093: else if (first_reg < 16)
1094: fprintf (file, "\tstm r%d,%d(r1)\n", first_reg, reg_save_offset);
1095:
1096: /* Set up pointer to data area if it is needed. */
1097: if (romp_using_r14 ())
1098: fprintf (file, "\tcas r14,r0,r0\n");
1099:
1100: /* Set up frame pointer if needed. */
1101: if (frame_pointer_needed)
1102: fprintf (file, "\tcal r13,-%d(r1)\n", romp_sa_size () + 64);
1103:
1104: /* Push stack if neeeded. There are a couple of ways of doing this. */
1105: if (romp_pushes_stack ())
1106: {
1107: if (size >= 32768)
1108: {
1109: if (size >= 65536)
1110: {
1111: fprintf (file, "\tcau r0,%d(r0)\n", size >> 16);
1112: fprintf (file, "\toil r0,r0,%d\n", size & 0xffff);
1113: }
1114: else
1115: fprintf (file, "\tcal16 r0,%d(r0)\n", size);
1116: fprintf (file, "\ts r1,r0\n");
1117: }
1118: else
1119: fprintf (file, "\tcal r1,-%d(r1)\n", size);
1120: }
1121:
1122: /* Save floating-point registers. */
1123: output_loadsave_fpregs (file, USE,
1124: plus_constant (stack_pointer_rtx, fp_save));
1125: }
1126:
1127: /* Write function epilogue. */
1128:
1129: void
1130: output_epilog (file, size)
1131: FILE *file;
1132: int size;
1133: {
1134: int first_reg = first_reg_to_save();
1135: int pushes_stack = romp_pushes_stack ();
1136: int reg_save_offset = - ((16 - first_reg) + 1 + 4 + 4) * 4;
1137: int total_size = (size + romp_sa_size ()
1138: + current_function_outgoing_args_size);
1139: int fp_save = size + current_function_outgoing_args_size;
1140: int long_frame = total_size >= 32768;
1141: rtx insn = get_last_insn ();
1142: int write_code = 1;
1143:
1144: int nargs = 0; /* words of arguments */
1145: tree argptr;
1146:
1147: /* Compute the number of words of arguments. Since this is just for
1148: the traceback table, we ignore arguments that don't have a size or
1149: don't have a fixed size. */
1150:
1151: for (argptr = DECL_ARGUMENTS (current_function_decl);
1152: argptr; argptr = TREE_CHAIN (argptr))
1153: {
1154: int this_size = int_size_in_bytes (TREE_TYPE (argptr));
1155:
1156: if (this_size > 0)
1157: nargs += (this_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1158: }
1159:
1160: /* If the last insn was a BARRIER, we don't have to write anything except
1161: the trace table. */
1162: if (GET_CODE (insn) == NOTE)
1163: insn = prev_nonnote_insn (insn);
1164: if (insn && GET_CODE (insn) == BARRIER)
1165: write_code = 0;
1166:
1167: /* Restore floating-point registers. */
1168: if (write_code)
1169: output_loadsave_fpregs (file, CLOBBER,
1170: gen_rtx (PLUS, Pmode, gen_rtx (REG, Pmode, 1),
1171: gen_rtx (CONST_INT, VOIDmode, fp_save)));
1172:
1173: /* If we push the stack and do not have size > 32K, adjust the register
1174: save location to the current position of sp. Otherwise, if long frame,
1175: restore sp from fp. */
1176: if (pushes_stack && ! long_frame)
1177: reg_save_offset += total_size;
1178: else if (long_frame && write_code)
1179: fprintf (file, "\tcal r1,%d(r13)\n", romp_sa_size () + 64);
1180:
1181: /* Restore registers. */
1182: if (first_reg == 15 && write_code)
1183: fprintf (file, "\tl r15,%d(r1)\n", reg_save_offset);
1184: else if (first_reg < 16 && write_code)
1185: fprintf (file, "\tlm r%d,%d(r1)\n", first_reg, reg_save_offset);
1186: if (first_reg == 16) first_reg = 0;
1187:
1188: /* Handle popping stack, if needed and write debug table entry. */
1189: if (pushes_stack)
1190: {
1191: if (write_code)
1192: {
1193: if (long_frame)
1194: fprintf (file, "\tbr r15\n");
1195: else
1196: fprintf (file, "\tbrx r15\n\tcal r1,%d(r1)\n", total_size);
1197: }
1198: fprintf (file, "\t.long 0x%x\n", 0xdf07df08 + first_reg * 0x10);
1199:
1200: if (nargs > 15) nargs = 15;
1201: if (frame_pointer_needed)
1202: fprintf (file, "\t.byte 0x%xd, 53\n", nargs);
1203: else
1204: fprintf (file, "\t.short 0x%x100\n", nargs);
1205: }
1206: else
1207: {
1208: if (write_code)
1209: fprintf (file, "\tbr r15\n");
1210: fprintf (file, "\t.long 0xdf02df00\n");
1211: }
1212:
1213: /* Output any pending floating-point operations. */
1214: output_fpops (file);
1215: }
1216:
1217: /* For the ROMP we need to make new SYMBOL_REFs for the actual name of a
1218: called routine. To keep them unique we maintain a hash table of all
1219: that have been created so far. */
1220:
1221: struct symref_hashent {
1222: rtx symref; /* Created SYMBOL_REF rtx. */
1223: struct symref_hashent *next; /* Next with same hash code. */
1224: };
1225:
1226: #define SYMHASHSIZE 151
1227: #define HASHBITS 65535
1228:
1229: /* Define the hash table itself. */
1230:
1231: static struct symref_hashent *symref_hash_table[SYMHASHSIZE];
1232:
1233: /* Given a name (allocatable in temporary storage), return a SYMBOL_REF
1234: for the name. The rtx is allocated from the current rtl_obstack, while
1235: the name string is allocated from the permanent obstack. */
1236: rtx
1237: get_symref (name)
1238: register char *name;
1239: {
1240: extern struct obstack permanent_obstack;
1241: register char *sp = name;
1242: unsigned int hash = 0;
1243: struct symref_hashent *p, **last_p;
1244:
1245: /* Compute the hash code for the string. */
1246: while (*sp)
1247: hash = (hash << 4) + *sp++;
1248:
1249: /* Search for a matching entry in the hash table, keeping track of the
1250: insertion location as we do so. */
1251: hash = (hash & HASHBITS) % SYMHASHSIZE;
1252: for (last_p = &symref_hash_table[hash], p = *last_p;
1253: p; last_p = &p->next, p = *last_p)
1254: if (strcmp (name, XSTR (p->symref, 0)) == 0)
1255: break;
1256:
1257: /* If couldn't find matching SYMBOL_REF, make a new one. */
1258: if (p == 0)
1259: {
1260: /* Ensure SYMBOL_REF will stay around. */
1261: end_temporary_allocation ();
1262: p = *last_p = (struct symref_hashent *)
1263: permalloc (sizeof (struct symref_hashent));
1264: p->symref = gen_rtx (SYMBOL_REF, Pmode,
1265: obstack_copy0 (&permanent_obstack,
1266: name, strlen (name)));
1267: p->next = 0;
1268: resume_temporary_allocation ();
1269: }
1270:
1271: return p->symref;
1272: }
1273:
1274: /* Validate the precision of a floating-point operation.
1275:
1276: We merge conversions from integers and between floating-point modes into
1277: the insn. However, this must not effect the desired precision of the
1278: insn. The RT floating-point system uses the widest of the operand modes.
1279: If this should be a double-precision insn, ensure that one operand
1280: passed to the floating-point processor has double mode.
1281:
1282: Note that since we don't check anything if the mode is single precision,
1283: it, strictly speaking, isn't necessary to call this for those insns.
1284: However, we do so in case something else needs to be checked in the
1285: future.
1286:
1287: This routine returns 1 if the operation is OK. */
1288:
1289: int
1290: check_precision (opmode, op1, op2)
1291: enum machine_mode opmode;
1292: rtx op1, op2;
1293: {
1294: if (opmode == SFmode)
1295: return 1;
1296:
1297: /* If operand is not a conversion from an integer mode or an extension from
1298: single-precision, it must be a double-precision value. */
1299: if (GET_CODE (op1) != FLOAT && GET_CODE (op1) != FLOAT_EXTEND)
1300: return 1;
1301:
1302: if (op2 && GET_CODE (op2) != FLOAT && GET_CODE (op2) != FLOAT_EXTEND)
1303: return 1;
1304:
1305: return 0;
1306: }
1307:
1308: /* Floating-point on the RT is done by creating an operation block in the data
1309: area that describes the operation. If two floating-point operations are the
1310: same in a single function, they can use the same block.
1311:
1312: These routines are responsible for managing these blocks. */
1313:
1314: /* Structure to describe a floating-point operation. */
1315:
1316: struct fp_op {
1317: struct fp_op *next_same_hash; /* Next op with same hash code. */
1318: struct fp_op *next_in_mem; /* Next op in memory. */
1319: int mem_offset; /* Offset from data area. */
1320: short size; /* Size of block in bytes. */
1321: short noperands; /* Number of operands in block. */
1322: rtx ops[3]; /* RTL for operands. */
1323: enum rtx_code opcode; /* Operation being performed. */
1324: };
1325:
1326: /* Size of hash table. */
1327: #define FP_HASH_SIZE 101
1328:
1329: /* Hash table of floating-point operation blocks. */
1330: static struct fp_op *fp_hash_table[FP_HASH_SIZE];
1331:
1332: /* First floating-point block in data area. */
1333: static struct fp_op *first_fpop;
1334:
1335: /* Last block in data area so far. */
1336: static struct fp_op *last_fpop_in_mem;
1337:
1338: /* Subroutine number in file, to get unique "LF" labels. */
1339: static int subr_number = 0;
1340:
1341: /* Current word offset in data area (includes header and any constant pool). */
1342: int data_offset;
1343:
1344: /* Compute hash code for an RTX used in floating-point. */
1345:
1346: static unsigned int
1347: hash_rtx (x)
1348: register rtx x;
1349: {
1350: register unsigned int hash = (((int) GET_CODE (x) << 10)
1351: + ((int) GET_MODE (x) << 20));
1352: register int i;
1353: register char *fmt = GET_RTX_FORMAT (GET_CODE (x));
1354:
1355: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
1356: if (fmt[i] == 'e')
1357: hash += hash_rtx (XEXP (x, i));
1358: else if (fmt[i] == 'u')
1359: hash += (int) XEXP (x, i);
1360: else if (fmt[i] == 'i')
1361: hash += XINT (x, i);
1362: else if (fmt[i] == 's')
1363: hash += (int) XSTR (x, i);
1364:
1365: return hash;
1366: }
1367:
1368: /* Given an operation code and up to three operands, return a character string
1369: corresponding to the code to emit to branch to a floating-point operation
1370: block. INSN is provided to see if the delay slot has been filled or not.
1371:
1372: A new floating-point operation block is created if this operation has not
1373: been seen before. */
1374:
1375: char *
1376: output_fpop (code, op0, op1, op2, insn)
1377: enum rtx_code code;
1378: rtx op0, op1, op2;
1379: rtx insn;
1380: {
1381: static char outbuf[40];
1382: unsigned int hash, hash0, hash1, hash2;
1383: int size, i;
1384: register struct fp_op *fpop, *last_fpop;
1385: int dyadic = (op2 != 0);
1386: enum machine_mode opmode;
1387: int noperands;
1388: rtx tem;
1389: unsigned int tem_hash;
1390: int fr0_avail = 0;
1391:
1392: /* Compute hash code for each operand. If the operation is commutative,
1393: put the one with the smaller hash code first. This will make us see
1394: more operations as identical. */
1395: hash0 = op0 ? hash_rtx (op0) : 0;
1396: hash1 = op1 ? hash_rtx (op1) : 0;
1397: hash2 = op2 ? hash_rtx (op2) : 0;
1398:
1399: if (hash0 > hash1 && code == EQ)
1400: {
1401: tem = op0; op0 = op1; op1 = tem;
1402: tem_hash = hash0; hash0 = hash1; hash1 = tem_hash;
1403: }
1404: else if (hash1 > hash2 && (code == PLUS || code == MULT))
1405: {
1406: tem = op1; op1 = op2; op2 = tem;
1407: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
1408: }
1409:
1410: /* If operation is commutative and the first and third operands are equal,
1411: swap the second and third operands. Note that we must consider two
1412: operands equal if they are the same register even if different modes. */
1413: if (op2 && (code == PLUS || code == MULT)
1414: && (rtx_equal_p (op0, op2)
1415: || (GET_CODE (op0) == REG && GET_CODE (op2) == REG
1416: && REGNO (op0) == REGNO (op2))))
1417: {
1418: tem = op1; op1 = op2; op2 = tem;
1419: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
1420: }
1421:
1422: /* If the first and second operands are the same, merge them. Don't do this
1423: for SFmode or SImode in general registers because this triggers a bug in
1424: the RT fp code. */
1425: if (op1 && rtx_equal_p (op0, op1)
1426: && code != EQ && code != GE && code != SET
1427: && ((GET_MODE (op1) != SFmode && GET_MODE (op1) != SImode)
1428: || GET_CODE (op0) != REG || FP_REGNO_P (REGNO (op0))))
1429: {
1430: op1 = op2;
1431: op2 = 0;
1432: }
1433:
1434: noperands = 1 + (op1 != 0) + (op2 != 0);
1435:
1436: /* Compute hash code for entire expression and see if operation block
1437: already exists. */
1438: hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2;
1439:
1440: hash %= FP_HASH_SIZE;
1441: for (fpop = fp_hash_table[hash], last_fpop = 0;
1442: fpop;
1443: last_fpop = fpop, fpop = fpop->next_same_hash)
1444: if (fpop->opcode == code && noperands == fpop->noperands
1445: && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0]))
1446: && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1]))
1447: && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2])))
1448: goto win;
1449:
1450: /* We have never seen this operation before. */
1451: fpop = (struct fp_op *) oballoc (sizeof (struct fp_op));
1452: fpop->mem_offset = data_offset;
1453: fpop->opcode = code;
1454: fpop->noperands = noperands;
1455: fpop->ops[0] = op0;
1456: fpop->ops[1] = op1;
1457: fpop->ops[2] = op2;
1458:
1459: /* Compute the size using the rules in Appendix A of the RT Linkage
1460: Convention (4.3/RT-PSD:5) manual. These rules are a bit ambiguous,
1461: but if we guess wrong, it will effect only efficiency, not correctness. */
1462:
1463: /* Size = 24 + 32 for each non-fp (or fr7) */
1464: size = 24;
1465: if (op0 && (GET_CODE (op0) != REG
1466: || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23))
1467: size += 32;
1468:
1469: if (op1 && (GET_CODE (op1) != REG
1470: || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23))
1471: size += 32;
1472:
1473: if (op2 && (GET_CODE (op2) != REG
1474: || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23))
1475: size += 32;
1476:
1477: /* Size + 12 for each conversion. First get operation mode. */
1478: if ((op0 && GET_MODE (op0) == DFmode)
1479: || (op1 && GET_MODE (op1) == DFmode)
1480: || (op2 && GET_MODE (op2) == DFmode))
1481: opmode = DFmode;
1482: else
1483: opmode = SFmode;
1484:
1485: if (op0 && GET_MODE (op0) != opmode)
1486: size += 12;
1487: if (op1 && GET_MODE (op1) != opmode)
1488: size += 12;
1489: if (op2 && GET_MODE (op2) != opmode)
1490: size += 12;
1491:
1492: /* 12 more if first and third operand types not the same. */
1493: if (op2 && GET_MODE (op0) != GET_MODE (op2))
1494: size += 12;
1495:
1496: /* CMP and CMPT need additional. Also, compute size of save/restore here. */
1497: if (code == EQ)
1498: size += 32;
1499: else if (code == GE)
1500: size += 64;
1501: else if (code == USE || code == CLOBBER)
1502: {
1503: /* 34 + 24 for each additional register plus 8 if fr7 saved. (We
1504: call it 36 because we need to keep the block length a multiple
1505: of four. */
1506: size = 36 - 24;
1507: for (i = 0; i <= 7; i++)
1508: if (INTVAL (op0) & (1 << (7-i)))
1509: size += 24 + 8 * (i == 7);
1510: }
1511:
1512: /* We provide no general-purpose scratch registers. */
1513: size +=16;
1514:
1515: /* No floating-point scratch registers are provided. Compute extra
1516: length due to this. This logic is that shown in the referenced
1517: appendix. */
1518:
1519: i = 0;
1520: if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
1521: i++;
1522: if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1)))
1523: i++;
1524: if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1525: i++;
1526:
1527: if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17)
1528: && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17)
1529: && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17))
1530: fr0_avail = 1;
1531:
1532: if (dyadic)
1533: {
1534: if (i == 0)
1535: size += fr0_avail ? 64 : 112;
1536: else if (fpop->noperands == 2 && i == 1)
1537: size += fr0_avail ? 0 : 64;
1538: else if (fpop->noperands == 3)
1539: {
1540: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))
1541: && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1542: {
1543: if (REGNO (op0) == REGNO (op2))
1544: #if 1
1545: /* This triggers a bug on the RT. */
1546: abort ();
1547: #else
1548: size += fr0_avail ? 0 : 64;
1549: #endif
1550: }
1551: else
1552: {
1553: i = 0;
1554: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
1555: i++;
1556: if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1557: i++;
1558: if (i == 0)
1559: size += fr0_avail ? 64 : 112;
1560: else if (i == 1)
1561: size += fr0_avail ? 0 : 64;
1562: }
1563: }
1564: }
1565: else if (code != USE && code != CLOBBER
1566: && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0))))
1567: size += 64;
1568:
1569: if (! TARGET_FULL_FP_BLOCKS)
1570: {
1571: /* If we are not to pad the blocks, just compute its actual length. */
1572: size = 12; /* Header + opcode */
1573: if (code == USE || code == CLOBBER)
1574: size += 2;
1575: else
1576: {
1577: if (op0) size += 2;
1578: if (op1) size += 2;
1579: if (op2) size += 2;
1580: }
1581:
1582: /* If in the middle of a word, round. */
1583: if (size % UNITS_PER_WORD)
1584: size += 2;
1585:
1586: /* Handle any immediates. */
1587: if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG)
1588: size += 4;
1589: if (op1 && GET_CODE (op1) != REG)
1590: size += 4;
1591: if (op2 && GET_CODE (op2) != REG)
1592: size += 4;
1593:
1594: if (code != USE && code != CLOBBER &&
1595: op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode)
1596: size += 4;
1597: if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode)
1598: size += 4;
1599: if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode)
1600: size += 4;
1601: }
1602:
1603: /* Done with size computation! Chain this in. */
1604: fpop->size = size;
1605: data_offset += size / UNITS_PER_WORD;
1606: fpop->next_in_mem = 0;
1607: fpop->next_same_hash = 0;
1608:
1609: if (last_fpop_in_mem)
1610: last_fpop_in_mem->next_in_mem = fpop;
1611: else
1612: first_fpop = fpop;
1613: last_fpop_in_mem = fpop;
1614:
1615: if (last_fpop)
1616: last_fpop->next_same_hash = fpop;
1617: else
1618: fp_hash_table[hash] = fpop;
1619:
1620: win:
1621: /* FPOP describes the operation to be performed. Return a string to branch
1622: to it. */
1623: if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
1624: sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15",
1625: fpop->mem_offset * UNITS_PER_WORD,
1626: dbr_sequence_length () ? "x" : "");
1627: else
1628: sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15",
1629: subr_number, fpop->mem_offset * UNITS_PER_WORD,
1630: dbr_sequence_length () ? "x" : "");
1631: return outbuf;
1632: }
1633:
1634: /* If necessary, output a floating-point operation to save or restore all
1635: floating-point registers.
1636:
1637: file is the file to write the operation to, CODE is USE for save, CLOBBER
1638: for restore, and ADDR is the address of the same area, as RTL. */
1639:
1640: static void
1641: output_loadsave_fpregs (file, code, addr)
1642: FILE *file;
1643: enum rtx_code code;
1644: rtx addr;
1645: {
1646: register int i;
1647: register int mask = 0;
1648:
1649: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++)
1650: if (regs_ever_live[i + 17])
1651: mask |= 1 << (7 - i);
1652:
1653: if (mask)
1654: fprintf (file, "\t%s\n",
1655: output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask),
1656: gen_rtx (MEM, Pmode, addr),
1657: 0, const0_rtx));
1658:
1659: }
1660:
1661: /* Output any floating-point operations at the end of the routine. */
1662:
1663: static void
1664: output_fpops (file)
1665: FILE *file;
1666: {
1667: register struct fp_op *fpop;
1668: register int size_so_far;
1669: register int i;
1670: rtx immed[3];
1671:
1672: if (first_fpop == 0)
1673: return;
1674:
1675: data_section ();
1676:
1677: ASM_OUTPUT_ALIGN (file, 2);
1678:
1679: for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem)
1680: {
1681: if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
1682: fprintf (file, "# data area offset = %d\n",
1683: fpop->mem_offset * UNITS_PER_WORD);
1684: else
1685: fprintf (file, "L%dF%d:\n",
1686: subr_number, fpop->mem_offset * UNITS_PER_WORD);
1687:
1688: fprintf (file, "\tcas r0,r15,r0\n");
1689: fprintf (file, "\t.long FPGLUE\n");
1690: switch (fpop->opcode)
1691: {
1692: case USE:
1693: fprintf (file, "\t.byte 0x1d\t# STOREM\n");
1694: break;
1695: case CLOBBER:
1696: fprintf (file, "\t.byte 0x0f\t# LOADM\n");
1697: break;
1698: case ABS:
1699: fprintf (file, "\t.byte 0x00\t# ABS\n");
1700: break;
1701: case PLUS:
1702: fprintf (file, "\t.byte 0x02\t# ADD\n");
1703: break;
1704: case EQ:
1705: fprintf (file, "\t.byte 0x07\t# CMP\n");
1706: break;
1707: case GE:
1708: fprintf (file, "\t.byte 0x08\t# CMPT\n");
1709: break;
1710: case DIV:
1711: fprintf (file, "\t.byte 0x0c\t# DIV\n");
1712: break;
1713: case SET:
1714: fprintf (file, "\t.byte 0x14\t# MOVE\n");
1715: break;
1716: case MULT:
1717: fprintf (file, "\t.byte 0x15\t# MUL\n");
1718: break;
1719: case NEG:
1720: fprintf (file, "\t.byte 0x16\t# NEG\n");
1721: break;
1722: case SQRT:
1723: fprintf (file, "\t.byte 0x1c\t# SQRT\n");
1724: break;
1725: case MINUS:
1726: fprintf (file, "\t.byte 0x1e\t# SUB\n");
1727: break;
1728: default:
1729: abort ();
1730: }
1731:
1732: fprintf (file, "\t.byte %d\n", fpop->noperands);
1733: fprintf (file, "\t.short 0x8001\n");
1734:
1735: if ((fpop->ops[0] == 0
1736: || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17)
1737: && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG
1738: || REGNO(fpop->ops[1]) != 17)
1739: && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG
1740: || REGNO(fpop->ops[2]) != 17))
1741: fprintf (file, "\t.byte %d, 0x80\n", fpop->size);
1742: else
1743: fprintf (file, "\t.byte %d, 0\n", fpop->size);
1744: size_so_far = 12;
1745: for (i = 0; i < fpop->noperands; i++)
1746: {
1747: register int type;
1748: register int opbyte;
1749: register char *desc0;
1750: char desc1[50];
1751:
1752: immed[i] = 0;
1753: switch (GET_MODE (fpop->ops[i]))
1754: {
1755: case SImode:
1756: case VOIDmode:
1757: desc0 = "int";
1758: type = 0;
1759: break;
1760: case SFmode:
1761: desc0 = "float";
1762: type = 2;
1763: break;
1764: case DFmode:
1765: desc0 = "double";
1766: type = 3;
1767: break;
1768: default:
1769: abort ();
1770: }
1771:
1772: switch (GET_CODE (fpop->ops[i]))
1773: {
1774: case REG:
1775: strcpy(desc1, reg_names[REGNO (fpop->ops[i])]);
1776: if (FP_REGNO_P (REGNO (fpop->ops[i])))
1777: {
1778: type += 0x10;
1779: opbyte = REGNO (fpop->ops[i]) - 17;
1780: }
1781: else
1782: {
1783: type += 0x00;
1784: opbyte = REGNO (fpop->ops[i]);
1785: if (type == 3)
1786: opbyte = (opbyte << 4) + opbyte + 1;
1787: }
1788: break;
1789:
1790: case MEM:
1791: type += 0x30;
1792: if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS)
1793: {
1794: immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1);
1795: opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0));
1796: if (GET_CODE (immed[i]) == CONST_INT)
1797: sprintf (desc1, "%d(%s)", INTVAL (immed[i]),
1798: reg_names[opbyte]);
1799: else
1800: sprintf (desc1, "<memory> (%s)", reg_names[opbyte]);
1801: }
1802: else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG)
1803: {
1804: opbyte = REGNO (XEXP (fpop->ops[i], 0));
1805: immed[i] = const0_rtx;
1806: sprintf (desc1, "(%s)", reg_names[opbyte]);
1807: }
1808: else
1809: {
1810: immed[i] = XEXP (fpop->ops[i], 0);
1811: opbyte = 0;
1812: sprintf(desc1, "<memory>");
1813: }
1814: break;
1815:
1816: case CONST_INT:
1817: case CONST_DOUBLE:
1818: case CONST:
1819: case SYMBOL_REF:
1820: case LABEL_REF:
1821: type += 0x20;
1822: opbyte = 0;
1823: immed[i] = fpop->ops[i];
1824: desc1[0] = '$';
1825: desc1[1] = '\0';
1826: break;
1827:
1828: default:
1829: abort ();
1830: }
1831:
1832: /* Save/restore is special. */
1833: if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER))
1834: type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0;
1835:
1836: fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n",
1837: type, opbyte, desc0, desc1);
1838:
1839: size_so_far += 2;
1840: }
1841:
1842: /* If in the middle of a word, round. */
1843: if (size_so_far % UNITS_PER_WORD)
1844: {
1845: fprintf (file, "\t.space 2\n");
1846: size_so_far += 2;
1847: }
1848:
1849: for (i = 0; i < fpop->noperands; i++)
1850: if (immed[i])
1851: switch (GET_MODE (immed[i]))
1852: {
1853: case SImode:
1854: case VOIDmode:
1855: size_so_far += 4;
1856: fprintf (file, "\t.long ");
1857: output_addr_const (file, immed[i]);
1858: fprintf (file, "\n");
1859: break;
1860:
1861: case DFmode:
1862: size_so_far += 4;
1863: case SFmode:
1864: size_so_far += 4;
1865: if (GET_CODE (immed[i]) == CONST_DOUBLE)
1866: {
1867: union real_extract u;
1868:
1869: bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u);
1870: if (GET_MODE (immed[i]) == DFmode)
1871: ASM_OUTPUT_DOUBLE (file, u.d);
1872: else
1873: ASM_OUTPUT_FLOAT (file, u.d);
1874: }
1875: else
1876: abort ();
1877: break;
1878:
1879: default:
1880: abort ();
1881: }
1882:
1883: if (size_so_far != fpop->size)
1884: {
1885: if (TARGET_FULL_FP_BLOCKS)
1886: fprintf (file, "\t.space %d\n", fpop->size - size_so_far);
1887: else
1888: abort ();
1889: }
1890: }
1891:
1892: /* Update for next subroutine. */
1893: subr_number++;
1894: text_section ();
1895: }
1896:
1897: /* Initialize floating-point operation table. */
1898:
1899: static void
1900: init_fpops()
1901: {
1902: register int i;
1903:
1904: first_fpop = last_fpop_in_mem = 0;
1905: for (i = 0; i < FP_HASH_SIZE; i++)
1906: fp_hash_table[i] = 0;
1907: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.