|
|
1.1 root 1: /* Subroutines used for code generation on ROMP.
2: Copyright (C) 1990, 1991 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 converstion 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 delimeter 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: for (argptr = DECL_ARGUMENTS (current_function_decl);
1148: argptr; argptr = TREE_CHAIN (argptr))
1149: nargs += ((TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (argptr)))
1150: + BITS_PER_WORD - 1) / BITS_PER_WORD);
1151:
1152: /* If the last insn was a BARRIER, we don't have to write anything except
1153: the trace table. */
1154: if (GET_CODE (insn) == NOTE)
1155: insn = prev_nonnote_insn (insn);
1156: if (insn && GET_CODE (insn) == BARRIER)
1157: write_code = 0;
1158:
1159: /* Restore floating-point registers. */
1160: if (write_code)
1161: output_loadsave_fpregs (file, CLOBBER,
1162: gen_rtx (PLUS, Pmode, gen_rtx (REG, Pmode, 1),
1163: gen_rtx (CONST_INT, VOIDmode, fp_save)));
1164:
1165: /* If we push the stack and do not have size > 32K, adjust the register
1166: save location to the current position of sp. Otherwise, if long frame,
1167: restore sp from fp. */
1168: if (pushes_stack && ! long_frame)
1169: reg_save_offset += total_size;
1170: else if (long_frame && write_code)
1171: fprintf (file, "\tcal r1,%d(r13)\n", romp_sa_size () + 64);
1172:
1173: /* Restore registers. */
1174: if (first_reg == 15 && write_code)
1175: fprintf (file, "\tl r15,%d(r1)\n", reg_save_offset);
1176: else if (first_reg < 16 && write_code)
1177: fprintf (file, "\tlm r%d,%d(r1)\n", first_reg, reg_save_offset);
1178: if (first_reg == 16) first_reg = 0;
1179:
1180: /* Handle popping stack, if needed and write debug table entry. */
1181: if (pushes_stack)
1182: {
1183: if (write_code)
1184: {
1185: if (long_frame)
1186: fprintf (file, "\tbr r15\n");
1187: else
1188: fprintf (file, "\tbrx r15\n\tcal r1,%d(r1)\n", total_size);
1189: }
1190: fprintf (file, "\t.long 0x%x\n", 0xdf07df08 + first_reg * 0x10);
1191:
1192: if (nargs > 15) nargs = 15;
1193: if (frame_pointer_needed)
1194: fprintf (file, "\t.byte 0x%xd, 53\n", nargs);
1195: else
1196: fprintf (file, "\t.short 0x%x100\n", nargs);
1197: }
1198: else
1199: {
1200: if (write_code)
1201: fprintf (file, "\tbr r15\n");
1202: fprintf (file, "\t.long 0xdf02df00\n");
1203: }
1204:
1205: /* Output any pending floating-point operations. */
1206: if (write_code)
1207: output_fpops (file);
1208: }
1209:
1210: /* For the ROMP we need to make new SYMBOL_REFs for the actual name of a
1211: called routine. To keep them unique we maintain a hash table of all
1212: that have been created so far. */
1213:
1214: struct symref_hashent {
1215: rtx symref; /* Created SYMBOL_REF rtx. */
1216: struct symref_hashent *next; /* Next with same hash code. */
1217: };
1218:
1219: #define SYMHASHSIZE 151
1220: #define HASHBITS 65535
1221:
1222: /* Define the hash table itself. */
1223:
1224: static struct symref_hashent *symref_hash_table[SYMHASHSIZE];
1225:
1226: /* Given a name (allocatable in temporary storage), return a SYMBOL_REF
1227: for the name. The rtx is allocated from the current rtl_obstack, while
1228: the name string is allocated from the permanent obstack. */
1229: rtx
1230: get_symref (name)
1231: register char *name;
1232: {
1233: extern struct obstack permanent_obstack;
1234: register char *sp = name;
1235: unsigned int hash = 0;
1236: struct symref_hashent *p, **last_p;
1237:
1238: /* Compute the hash code for the string. */
1239: while (*sp)
1240: hash = (hash << 4) + *sp++;
1241:
1242: /* Search for a matching entry in the hash table, keeping track of the
1243: insertion location as we do so. */
1244: hash = (hash & HASHBITS) % SYMHASHSIZE;
1245: for (last_p = &symref_hash_table[hash], p = *last_p;
1246: p; last_p = &p->next, p = *last_p)
1247: if (strcmp (name, XSTR (p->symref, 0)) == 0)
1248: break;
1249:
1250: /* If couldn't find matching SYMBOL_REF, make a new one. */
1251: if (p == 0)
1252: {
1253: /* Ensure SYMBOL_REF will stay around. */
1254: end_temporary_allocation ();
1255: p = *last_p = (struct symref_hashent *)
1256: permalloc (sizeof (struct symref_hashent));
1257: p->symref = gen_rtx (SYMBOL_REF, Pmode,
1258: obstack_copy0 (&permanent_obstack,
1259: name, strlen (name)));
1260: p->next = 0;
1261: resume_temporary_allocation ();
1262: }
1263:
1264: return p->symref;
1265: }
1266:
1267: /* Validate the precision of a floating-point operation.
1268:
1269: We merge conversions from integers and between floating-point modes into
1270: the insn. However, this must not effect the desired precision of the
1271: insn. The RT floating-point system uses the widest of the operand modes.
1272: If this should be a double-precision insn, ensure that one operand
1273: passed to the floating-point processor has double mode.
1274:
1275: Note that since we don't check anything if the mode is single precision,
1276: it, strictly speaking, isn't necessary to call this for those insns.
1277: However, we do so in case something else needs to be checked in the
1278: future.
1279:
1280: This routine returns 1 if the operation is OK. */
1281:
1282: int
1283: check_precision (opmode, op1, op2)
1284: enum machine_mode opmode;
1285: rtx op1, op2;
1286: {
1287: if (opmode == SFmode)
1288: return 1;
1289:
1290: /* If operand is not a conversion from an integer mode or an extension from
1291: single-precision, it must be a double-precision value. */
1292: if (GET_CODE (op1) != FLOAT && GET_CODE (op1) != FLOAT_EXTEND)
1293: return 1;
1294:
1295: if (op2 && GET_CODE (op2) != FLOAT && GET_CODE (op2) != FLOAT_EXTEND)
1296: return 1;
1297:
1298: return 0;
1299: }
1300:
1301: /* Floating-point on the RT is done by creating an operation block in the data
1302: area that describes the operation. If two floating-point operations are the
1303: same in a single function, they can use the same block.
1304:
1305: These routines are responsible for managing these blocks. */
1306:
1307: /* Structure to describe a floating-point operation. */
1308:
1309: struct fp_op {
1310: struct fp_op *next_same_hash; /* Next op with same hash code. */
1311: struct fp_op *next_in_mem; /* Next op in memory. */
1312: int mem_offset; /* Offset from data area. */
1313: short size; /* Size of block in bytes. */
1314: short noperands; /* Number of operands in block. */
1315: rtx ops[3]; /* RTL for operands. */
1316: enum rtx_code opcode; /* Operation being performed. */
1317: };
1318:
1319: /* Size of hash table. */
1320: #define FP_HASH_SIZE 101
1321:
1322: /* Hash table of floating-point operation blocks. */
1323: static struct fp_op *fp_hash_table[FP_HASH_SIZE];
1324:
1325: /* First floating-point block in data area. */
1326: static struct fp_op *first_fpop;
1327:
1328: /* Last block in data area so far. */
1329: static struct fp_op *last_fpop_in_mem;
1330:
1331: /* Subroutine number in file, to get unique "LF" labels. */
1332: static int subr_number = 0;
1333:
1334: /* Current word offset in data area (includes header and any constant pool). */
1335: int data_offset;
1336:
1337: /* Compute hash code for an RTX used in floating-point. */
1338:
1339: static unsigned int
1340: hash_rtx (x)
1341: register rtx x;
1342: {
1343: register unsigned int hash = (((int) GET_CODE (x) << 10)
1344: + ((int) GET_MODE (x) << 20));
1345: register int i;
1346: register char *fmt = GET_RTX_FORMAT (GET_CODE (x));
1347:
1348: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
1349: if (fmt[i] == 'e')
1350: hash += hash_rtx (XEXP (x, i));
1351: else if (fmt[i] == 'u')
1352: hash += (int) XEXP (x, i);
1353: else if (fmt[i] == 'i')
1354: hash += XINT (x, i);
1355: else if (fmt[i] == 's')
1356: hash += (int) XSTR (x, i);
1357:
1358: return hash;
1359: }
1360:
1361: /* Given an operation code and up to three operands, return a character string
1362: corresponding to the code to emit to branch to a floating-point operation
1363: block. INSN is provided to see if the delay slot has been filled or not.
1364:
1365: A new floating-point operation block is created if this operation has not
1366: been seen before. */
1367:
1368: char *
1369: output_fpop (code, op0, op1, op2, insn)
1370: enum rtx_code code;
1371: rtx op0, op1, op2;
1372: rtx insn;
1373: {
1374: static char outbuf[40];
1375: unsigned int hash, hash0, hash1, hash2;
1376: int size, i;
1377: register struct fp_op *fpop, *last_fpop;
1378: int dyadic = (op2 != 0);
1379: enum machine_mode opmode;
1380: int noperands;
1381: rtx tem;
1382: unsigned int tem_hash;
1383: int fr0_avail = 0;
1384:
1385: /* Compute hash code for each operand. If the operation is commutative,
1386: put the one with the smaller hash code first. This will make us see
1387: more operations as identical. */
1388: hash0 = op0 ? hash_rtx (op0) : 0;
1389: hash1 = op1 ? hash_rtx (op1) : 0;
1390: hash2 = op2 ? hash_rtx (op2) : 0;
1391:
1392: if (hash0 > hash1 && code == EQ)
1393: {
1394: tem = op0; op0 = op1; op1 = tem;
1395: tem_hash = hash0; hash0 = hash1; hash1 = tem_hash;
1396: }
1397: else if (hash1 > hash2 && (code == PLUS || code == MULT))
1398: {
1399: tem = op1; op1 = op2; op2 = tem;
1400: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
1401: }
1402:
1403: /* If operation is commutative and the first and third operands are equal,
1404: swap the second and third operands. Note that we must consider two
1405: operands equal if they are the same register even if different modes. */
1406: if (op2 && (code == PLUS || code == MULT)
1407: && (rtx_equal_p (op0, op2)
1408: || (GET_CODE (op0) == REG && GET_CODE (op2) == REG
1409: && REGNO (op0) == REGNO (op2))))
1410: {
1411: tem = op1; op1 = op2; op2 = tem;
1412: tem_hash = hash1; hash1 = hash2; hash2 = tem_hash;
1413: }
1414:
1415: /* If the first and second operands are the same, merge them. Don't do this
1416: for SFmode in general registers because this triggers a bug in the RT fp
1417: code. */
1418: if (op1 && rtx_equal_p (op0, op1)
1419: && code != EQ && code != GE && code != SET
1420: && (GET_MODE (op1) != SFmode || GET_CODE (op0) != REG
1421: || FP_REGNO_P (REGNO (op0))))
1422: {
1423: op1 = op2;
1424: op2 = 0;
1425: }
1426:
1427: noperands = 1 + (op1 != 0) + (op2 != 0);
1428:
1429: /* Compute hash code for entire expression and see if operation block
1430: already exists. */
1431: hash = ((int) code << 13) + (hash0 << 2) + (hash1 << 1) + hash2;
1432:
1433: hash %= FP_HASH_SIZE;
1434: for (fpop = fp_hash_table[hash], last_fpop = 0;
1435: fpop;
1436: last_fpop = fpop, fpop = fpop->next_same_hash)
1437: if (fpop->opcode == code && noperands == fpop->noperands
1438: && (op0 == 0 || rtx_equal_p (op0, fpop->ops[0]))
1439: && (op1 == 0 || rtx_equal_p (op1, fpop->ops[1]))
1440: && (op2 == 0 || rtx_equal_p (op2, fpop->ops[2])))
1441: goto win;
1442:
1443: /* We have never seen this operation before. */
1444: fpop = (struct fp_op *) oballoc (sizeof (struct fp_op));
1445: fpop->mem_offset = data_offset;
1446: fpop->opcode = code;
1447: fpop->noperands = noperands;
1448: fpop->ops[0] = op0;
1449: fpop->ops[1] = op1;
1450: fpop->ops[2] = op2;
1451:
1452: /* Compute the size using the rules in Appendix A of the RT Linkage
1453: Convention (4.3/RT-PSD:5) manual. These rules are a bit ambiguous,
1454: but if we guess wrong, it will effect only efficiency, not correctness. */
1455:
1456: /* Size = 24 + 32 for each non-fp (or fr7) */
1457: size = 24;
1458: if (op0 && (GET_CODE (op0) != REG
1459: || ! FP_REGNO_P (REGNO (op0)) || REGNO (op0) == 23))
1460: size += 32;
1461:
1462: if (op1 && (GET_CODE (op1) != REG
1463: || ! FP_REGNO_P (REGNO (op1)) || REGNO (op1) == 23))
1464: size += 32;
1465:
1466: if (op2 && (GET_CODE (op2) != REG
1467: || ! FP_REGNO_P (REGNO (op2)) || REGNO (op2) == 23))
1468: size += 32;
1469:
1470: /* Size + 12 for each conversion. First get operation mode. */
1471: if ((op0 && GET_MODE (op0) == DFmode)
1472: || (op1 && GET_MODE (op1) == DFmode)
1473: || (op2 && GET_MODE (op2) == DFmode))
1474: opmode = DFmode;
1475: else
1476: opmode = SFmode;
1477:
1478: if (op0 && GET_MODE (op0) != opmode)
1479: size += 12;
1480: if (op1 && GET_MODE (op1) != opmode)
1481: size += 12;
1482: if (op2 && GET_MODE (op2) != opmode)
1483: size += 12;
1484:
1485: /* 12 more if first and third operand types not the same. */
1486: if (op2 && GET_MODE (op0) != GET_MODE (op2))
1487: size += 12;
1488:
1489: /* CMP and CMPT need additional. Also, compute size of save/restore here. */
1490: if (code == EQ)
1491: size += 32;
1492: else if (code == GE)
1493: size += 64;
1494: else if (code == USE || code == CLOBBER)
1495: {
1496: /* 34 + 24 for each additional register plus 8 if fr7 saved. (We
1497: call it 36 because we need to keep the block length a multiple
1498: of four. */
1499: size = 36 - 24;
1500: for (i = 0; i <= 7; i++)
1501: if (INTVAL (op0) & (1 << (7-i)))
1502: size += 24 + 8 * (i == 7);
1503: }
1504:
1505: /* We provide no general-purpose scratch registers. */
1506: size +=16;
1507:
1508: /* No floating-point scratch registers are provided. Compute extra
1509: length due to this. This logic is that shown in the referenced
1510: appendix. */
1511:
1512: i = 0;
1513: if (op0 && GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
1514: i++;
1515: if (op1 && GET_CODE (op1) == REG && FP_REGNO_P (REGNO (op1)))
1516: i++;
1517: if (op2 && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1518: i++;
1519:
1520: if ((op0 == 0 || GET_CODE (op0) != REG || REGNO(op0) != 17)
1521: && (op1 == 0 || GET_CODE (op1) != REG || REGNO(op1) != 17)
1522: && (op2 == 0 || GET_CODE (op2) != REG || REGNO(op2) != 17))
1523: fr0_avail = 1;
1524:
1525: if (dyadic)
1526: {
1527: if (i == 0)
1528: size += fr0_avail ? 64 : 112;
1529: else if (fpop->noperands == 2 && i == 1)
1530: size += fr0_avail ? 0 : 64;
1531: else if (fpop->noperands == 3)
1532: {
1533: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0))
1534: && GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1535: {
1536: if (REGNO (op0) == REGNO (op2))
1537: #if 1
1538: /* This triggers a bug on the RT. */
1539: abort ();
1540: #else
1541: size += fr0_avail ? 0 : 64;
1542: #endif
1543: }
1544: else
1545: {
1546: i = 0;
1547: if (GET_CODE (op0) == REG && FP_REGNO_P (REGNO (op0)))
1548: i++;
1549: if (GET_CODE (op2) == REG && FP_REGNO_P (REGNO (op2)))
1550: i++;
1551: if (i == 0)
1552: size += fr0_avail ? 64 : 112;
1553: else if (i == 1)
1554: size += fr0_avail ? 0 : 64;
1555: }
1556: }
1557: }
1558: else if (code != USE && code != CLOBBER
1559: && (GET_CODE (op0) != REG || ! FP_REGNO_P (REGNO (op0))))
1560: size += 64;
1561:
1562: if (! TARGET_FULL_FP_BLOCKS)
1563: {
1564: /* If we are not to pad the blocks, just compute its actual length. */
1565: size = 12; /* Header + opcode */
1566: if (code == USE || code == CLOBBER)
1567: size += 2;
1568: else
1569: {
1570: if (op0) size += 2;
1571: if (op1) size += 2;
1572: if (op2) size += 2;
1573: }
1574:
1575: /* If in the middle of a word, round. */
1576: if (size % UNITS_PER_WORD)
1577: size += 2;
1578:
1579: /* Handle any immediates. */
1580: if (code != USE && code != CLOBBER && op0 && GET_CODE (op0) != REG)
1581: size += 4;
1582: if (op1 && GET_CODE (op1) != REG)
1583: size += 4;
1584: if (op2 && GET_CODE (op2) != REG)
1585: size += 4;
1586:
1587: if (code != USE && code != CLOBBER &&
1588: op0 && GET_CODE (op0) == CONST_DOUBLE && GET_MODE (op0) == DFmode)
1589: size += 4;
1590: if (op1 && GET_CODE (op1) == CONST_DOUBLE && GET_MODE (op1) == DFmode)
1591: size += 4;
1592: if (op2 && GET_CODE (op2) == CONST_DOUBLE && GET_MODE (op2) == DFmode)
1593: size += 4;
1594: }
1595:
1596: /* Done with size computation! Chain this in. */
1597: fpop->size = size;
1598: data_offset += size / UNITS_PER_WORD;
1599: fpop->next_in_mem = 0;
1600: fpop->next_same_hash = 0;
1601:
1602: if (last_fpop_in_mem)
1603: last_fpop_in_mem->next_in_mem = fpop;
1604: else
1605: first_fpop = fpop;
1606: last_fpop_in_mem = fpop;
1607:
1608: if (last_fpop)
1609: last_fpop->next_same_hash = fpop;
1610: else
1611: fp_hash_table[hash] = fpop;
1612:
1613: win:
1614: /* FPOP describes the operation to be performed. Return a string to branch
1615: to it. */
1616: if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
1617: sprintf (outbuf, "cal r15,%d(r14)\n\tbalr%s r15,r15",
1618: fpop->mem_offset * UNITS_PER_WORD,
1619: dbr_sequence_length () ? "x" : "");
1620: else
1621: sprintf (outbuf, "get r15,$L%dF%d\n\tbalr%s r15,r15",
1622: subr_number, fpop->mem_offset * UNITS_PER_WORD,
1623: dbr_sequence_length () ? "x" : "");
1624: return outbuf;
1625: }
1626:
1627: /* If necessary, output a floating-point operation to save or restore all
1628: floating-point registers.
1629:
1630: file is the file to write the operation to, CODE is USE for save, CLOBBER
1631: for restore, and ADDR is the address of the same area, as RTL. */
1632:
1633: static void
1634: output_loadsave_fpregs (file, code, addr)
1635: FILE *file;
1636: enum rtx_code code;
1637: rtx addr;
1638: {
1639: register int i;
1640: register int mask = 0;
1641:
1642: for (i = 2 + (TARGET_FP_REGS != 0); i <= 7; i++)
1643: if (regs_ever_live[i + 17])
1644: mask |= 1 << (7 - i);
1645:
1646: if (mask)
1647: fprintf (file, "\t%s\n",
1648: output_fpop (code, gen_rtx (CONST_INT, VOIDmode, mask),
1649: gen_rtx (MEM, Pmode, addr),
1650: 0, const0_rtx));
1651:
1652: }
1653:
1654: /* Output any floating-point operations at the end of the routine. */
1655:
1656: static void
1657: output_fpops (file)
1658: FILE *file;
1659: {
1660: register struct fp_op *fpop;
1661: register int size_so_far;
1662: register int i;
1663: rtx immed[3];
1664:
1665: if (first_fpop == 0)
1666: return;
1667:
1668: data_section ();
1669:
1670: ASM_OUTPUT_ALIGN (file, 2);
1671:
1672: for (fpop = first_fpop; fpop; fpop = fpop->next_in_mem)
1673: {
1674: if (fpop->mem_offset < 32768 / UNITS_PER_WORD)
1675: fprintf (file, "# data area offset = %d\n",
1676: fpop->mem_offset * UNITS_PER_WORD);
1677: else
1678: fprintf (file, "L%dF%d:\n",
1679: subr_number, fpop->mem_offset * UNITS_PER_WORD);
1680:
1681: fprintf (file, "\tcas r0,r15,r0\n");
1682: fprintf (file, "\t.long FPGLUE\n");
1683: switch (fpop->opcode)
1684: {
1685: case USE:
1686: fprintf (file, "\t.byte 0x1d\t# STOREM\n");
1687: break;
1688: case CLOBBER:
1689: fprintf (file, "\t.byte 0x0f\t# LOADM\n");
1690: break;
1691: case ABS:
1692: fprintf (file, "\t.byte 0x00\t# ABS\n");
1693: break;
1694: case PLUS:
1695: fprintf (file, "\t.byte 0x02\t# ADD\n");
1696: break;
1697: case EQ:
1698: fprintf (file, "\t.byte 0x07\t# CMP\n");
1699: break;
1700: case GE:
1701: fprintf (file, "\t.byte 0x08\t# CMPT\n");
1702: break;
1703: case DIV:
1704: fprintf (file, "\t.byte 0x0c\t# DIV\n");
1705: break;
1706: case SET:
1707: fprintf (file, "\t.byte 0x14\t# MOVE\n");
1708: break;
1709: case MULT:
1710: fprintf (file, "\t.byte 0x15\t# MUL\n");
1711: break;
1712: case NEG:
1713: fprintf (file, "\t.byte 0x16\t# NEG\n");
1714: break;
1715: case SQRT:
1716: fprintf (file, "\t.byte 0x1c\t# SQRT\n");
1717: break;
1718: case MINUS:
1719: fprintf (file, "\t.byte 0x1e\t# SUB\n");
1720: break;
1721: default:
1722: abort ();
1723: }
1724:
1725: fprintf (file, "\t.byte %d\n", fpop->noperands);
1726: fprintf (file, "\t.short 0x8001\n");
1727:
1728: if ((fpop->ops[0] == 0
1729: || GET_CODE (fpop->ops[0]) != REG || REGNO(fpop->ops[0]) != 17)
1730: && (fpop->ops[1] == 0 || GET_CODE (fpop->ops[1]) != REG
1731: || REGNO(fpop->ops[1]) != 17)
1732: && (fpop->ops[2] == 0 || GET_CODE (fpop->ops[2]) != REG
1733: || REGNO(fpop->ops[2]) != 17))
1734: fprintf (file, "\t.byte %d, 0x80\n", fpop->size);
1735: else
1736: fprintf (file, "\t.byte %d, 0\n", fpop->size);
1737: size_so_far = 12;
1738: for (i = 0; i < fpop->noperands; i++)
1739: {
1740: register int type;
1741: register int opbyte;
1742: register char *desc0;
1743: char desc1[50];
1744:
1745: immed[i] = 0;
1746: switch (GET_MODE (fpop->ops[i]))
1747: {
1748: case SImode:
1749: case VOIDmode:
1750: desc0 = "int";
1751: type = 0;
1752: break;
1753: case SFmode:
1754: desc0 = "float";
1755: type = 2;
1756: break;
1757: case DFmode:
1758: desc0 = "double";
1759: type = 3;
1760: break;
1761: default:
1762: abort ();
1763: }
1764:
1765: switch (GET_CODE (fpop->ops[i]))
1766: {
1767: case REG:
1768: strcpy(desc1, reg_names[REGNO (fpop->ops[i])]);
1769: if (FP_REGNO_P (REGNO (fpop->ops[i])))
1770: {
1771: type += 0x10;
1772: opbyte = REGNO (fpop->ops[i]) - 17;
1773: }
1774: else
1775: {
1776: type += 0x00;
1777: opbyte = REGNO (fpop->ops[i]);
1778: if (type == 3)
1779: opbyte = (opbyte << 4) + opbyte + 1;
1780: }
1781: break;
1782:
1783: case MEM:
1784: type += 0x30;
1785: if (GET_CODE (XEXP (fpop->ops[i], 0)) == PLUS)
1786: {
1787: immed[i] = XEXP (XEXP (fpop->ops[i], 0), 1);
1788: opbyte = REGNO (XEXP (XEXP (fpop->ops[i], 0), 0));
1789: if (GET_CODE (immed[i]) == CONST_INT)
1790: sprintf (desc1, "%d(%s)", INTVAL (immed[i]),
1791: reg_names[opbyte]);
1792: else
1793: sprintf (desc1, "<memory> (%s)", reg_names[opbyte]);
1794: }
1795: else if (GET_CODE (XEXP (fpop->ops[i], 0)) == REG)
1796: {
1797: opbyte = REGNO (XEXP (fpop->ops[i], 0));
1798: immed[i] = const0_rtx;
1799: sprintf (desc1, "(%s)", reg_names[opbyte]);
1800: }
1801: else
1802: {
1803: immed[i] = XEXP (fpop->ops[i], 0);
1804: opbyte = 0;
1805: sprintf(desc1, "<memory>");
1806: }
1807: break;
1808:
1809: case CONST_INT:
1810: case CONST_DOUBLE:
1811: case CONST:
1812: type += 0x20;
1813: opbyte = 0;
1814: immed[i] = fpop->ops[i];
1815: desc1[0] = '$';
1816: desc1[1] = '\0';
1817: break;
1818:
1819: default:
1820: abort ();
1821: }
1822:
1823: /* Save/restore is special. */
1824: if (i == 0 && (fpop->opcode == USE || fpop->opcode == CLOBBER))
1825: type = 0xff, opbyte = INTVAL (fpop->ops[0]), immed[i] = 0;
1826:
1827: fprintf (file, "\t.byte 0x%x,0x%x # (%s) %s\n",
1828: type, opbyte, desc0, desc1);
1829:
1830: size_so_far += 2;
1831: }
1832:
1833: /* If in the middle of a word, round. */
1834: if (size_so_far % UNITS_PER_WORD)
1835: {
1836: fprintf (file, "\t.space 2\n");
1837: size_so_far += 2;
1838: }
1839:
1840: for (i = 0; i < fpop->noperands; i++)
1841: if (immed[i])
1842: switch (GET_MODE (immed[i]))
1843: {
1844: case SImode:
1845: case VOIDmode:
1846: size_so_far += 4;
1847: fprintf (file, "\t.long ");
1848: output_addr_const (file, immed[i]);
1849: fprintf (file, "\n");
1850: break;
1851:
1852: case DFmode:
1853: size_so_far += 4;
1854: case SFmode:
1855: size_so_far += 4;
1856: if (GET_CODE (immed[i]) == CONST_DOUBLE)
1857: {
1858: union real_extract u;
1859:
1860: bcopy (&CONST_DOUBLE_LOW (immed[i]), &u, sizeof u);
1861: if (GET_MODE (immed[i]) == DFmode)
1862: ASM_OUTPUT_DOUBLE (file, u.d);
1863: else
1864: ASM_OUTPUT_FLOAT (file, u.d);
1865: }
1866: else
1867: abort ();
1868: break;
1869:
1870: default:
1871: abort ();
1872: }
1873:
1874: if (size_so_far != fpop->size)
1875: {
1876: if (TARGET_FULL_FP_BLOCKS)
1877: fprintf (file, "\t.space %d\n", fpop->size - size_so_far);
1878: else
1879: abort ();
1880: }
1881: }
1882:
1883: /* Update for next subroutine. */
1884: subr_number++;
1885: text_section ();
1886: }
1887:
1888: /* Initialize floating-point operation table. */
1889:
1890: static void
1891: init_fpops()
1892: {
1893: register int i;
1894:
1895: first_fpop = last_fpop_in_mem = 0;
1896: for (i = 0; i < FP_HASH_SIZE; i++)
1897: fp_hash_table[i] = 0;
1898: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.