|
|
1.1 root 1: /* Subroutines for insn-output.c for Convex.
1.1.1.2 root 2: Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc.
1.1 root 3:
4: This file is part of GNU CC.
5:
6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
1.1.1.3 ! root 18: the Free Software Foundation, 59 Temple Place - Suite 330,
! 19: Boston, MA 02111-1307, USA. */
1.1 root 20:
21: #include "config.h"
22: #include "tree.h"
23: #include "rtl.h"
24: #include "regs.h"
25: #include "hard-reg-set.h"
26: #include "real.h"
27: #include "insn-config.h"
28: #include "conditions.h"
29: #include "insn-flags.h"
30: #include "insn-attr.h"
31: #include "output.h"
32: #include "expr.h"
33:
34: #undef NULL
35: #include <stdio.h>
36:
37: /* Tables used in convex.h */
38:
39: char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1];
40: enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
41: enum reg_class reg_class_from_letter[256];
42:
43: /* Target cpu index. */
44:
45: int target_cpu;
46:
47: /* Boolean to keep track of whether the current section is .text or not.
48: Used by .align handler in convex.h. */
49:
50: int current_section_is_text;
51:
52: /* Communication between output_compare and output_condjump. */
53:
54: static rtx cmp_operand0, cmp_operand1;
55: static char cmp_modech;
56:
57: /* Forwards */
58:
59: static rtx frame_argblock;
60: static int frame_argblock_size;
61: static rtx convert_arg_pushes ();
62: static void expand_movstr_call ();
63:
64: /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */
65:
66: init_convex ()
67: {
68: int regno;
69:
70: /* Set A and S reg classes. */
71: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
72: if (A_REGNO_P (regno))
73: {
74: regno_ok_for_index_p[regno] = 1;
75: regno_reg_class[regno] = INDEX_REGS;
76: }
77: else
78: {
79: regno_ok_for_index_p[regno] = 0;
80: regno_reg_class[regno] = S_REGS;
81: }
82:
83: /* Can't index off the stack pointer, register 0. */
84: regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0;
85: regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS;
86:
87: /* Can't index off aliases of the stack pointer. */
88: regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1;
89: regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1;
90: regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0;
91: regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0;
92:
93: /* Can't index off hard reg -1 == pseudos not assigned */
94: regno_ok_for_index_p[-1] = 0;
95:
96: /* Set reg class letters */
97: reg_class_from_letter['a'] = A_REGS;
98: reg_class_from_letter['A'] = INDEX_REGS;
99: reg_class_from_letter['d'] = S_REGS;
100:
101: /* Turn off floating point exception enables in the psw. */
102: psw_disable_float ();
103: }
104:
105: psw_disable_float ()
106: {
107: #if __convex__ && __GNUC__
108: register int *p;
109: asm ("mov fp,%0" : "=a" (p));
110: while (p)
111: {
112: p[1] &= ~0x1000c400;
113: p = (int *) p[2];
114: }
115: #endif
116: }
117:
118: /* Here to output code for a compare insn. Output nothing, just
119: record the operands and their mode. */
120:
121: char *
122: output_cmp (operand0, operand1, modech)
123: rtx operand0, operand1;
124: char modech;
125: {
126: cmp_operand0 = operand0;
127: cmp_operand1 = operand1;
128: cmp_modech = modech;
129: return "";
130: }
131:
132: /* Output code for a conditional jump. The preceding instruction
133: is necessarily a compare. Output two instructions, for example
134: eq.w a1,a2
135: jbra.t L5
136: for
137: (cmpsi a1 a2)
138: (beq L5)
139: */
140:
141: char *
142: output_condjump (label, cond, jbr_sense)
143: rtx label;
144: char *cond;
145: char jbr_sense;
146: {
147: rtx operands[3];
148: char cmp_op[4];
149: char buf[80];
150: char jbr_regch;
151:
152: strcpy (cmp_op, cond);
153:
154: /* [BL] mean the value is being compared against immediate 0.
155: Use neg.x, which produces the same carry that eq.x #0 would if it
156: existed. In this case operands[1] is a scratch register, not a
157: compare operand. */
158:
159: if (cmp_modech == 'B' || cmp_modech == 'L')
160: {
161: cmp_modech = cmp_modech - 'A' + 'a';
162: strcpy (cmp_op, "neg");
163: }
164:
165: /* [WH] mean the value being compared resulted from "add.[wh] #-1,rk"
166: when rk was nonnegative -- we can omit equality compares against -1
167: or inequality compares against 0. */
168:
169: else if (cmp_modech == 'W' || cmp_modech == 'H')
170: {
171: if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx)
172: jbr_sense ^= 't' ^ 'f';
173: else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx)
174: ;
175: else
176: cmp_modech = cmp_modech - 'A' + 'a';
177: }
178:
179: /* Constant must be first; swap operands if necessary.
180: If lt, le, ltu, leu are swapped, change to le, lt, leu, ltu
181: and reverse the sense of the jump. */
182:
183: if (! REG_P (cmp_operand1))
184: {
185: operands[0] = cmp_operand1;
186: operands[1] = cmp_operand0;
187: if (cmp_op[0] == 'l')
188: {
189: cmp_op[1] ^= 'e' ^ 't';
190: jbr_sense ^= 't' ^ 'f';
191: }
192: }
193: else
194: {
195: operands[0] = cmp_operand0;
196: operands[1] = cmp_operand1;
197: }
198:
199: operands[2] = label;
200:
201: if (S_REG_P (operands[1]))
202: jbr_regch = 's';
203: else if (A_REG_P (operands[1]))
204: jbr_regch = 'a';
205: else
206: abort ();
207:
208: if (cmp_modech == 'W' || cmp_modech == 'H')
209: sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
210: else
211: sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2",
212: cmp_op, cmp_modech, jbr_regch, jbr_sense);
213: output_asm_insn (buf, operands);
214: return "";
215: }
216:
217: /* Return 1 if OP is valid for cmpsf.
218: In IEEE mode, +/- zero compares are not handled by
219: the immediate versions of eq.s and on some machines, lt.s, and le.s.
220: So disallow 0.0 as the immediate operand of xx.s compares in IEEE mode. */
221:
222: int
223: nonmemory_cmpsf_operand (op, mode)
224: rtx op;
225: enum machine_mode mode;
226: {
227: #if _IEEE_FLOAT_
228: if (op == CONST0_RTX (SFmode))
229: return 0;
230: #endif
231:
232: return nonmemory_operand (op, mode);
233: }
234:
235: /* Convex /bin/as does not like unary minus in some contexts.
236: Simplify CONST addresses to remove it. */
237:
238: rtx
239: simplify_for_convex (x)
240: rtx x;
241: {
242: switch (GET_CODE (x))
243: {
244: case MINUS:
245: if (GET_CODE (XEXP (x, 1)) == CONST_INT
246: && INTVAL (XEXP (x, 1)) < 0)
247: {
248: PUT_CODE (x, PLUS);
249: XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
250: }
251: break;
252:
253: case CONST:
254: return simplify_for_convex (XEXP (x, 0));
255: }
256:
257: return x;
258: }
259:
260: /* Routines to separate CONST_DOUBLEs into component parts. */
261:
262: int
263: const_double_high_int (x)
264: rtx x;
265: {
266: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
267: return CONST_DOUBLE_LOW (x);
268: else
269: return CONST_DOUBLE_HIGH (x);
270: }
271:
272: int
273: const_double_low_int (x)
274: rtx x;
275: {
276: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
277: return CONST_DOUBLE_HIGH (x);
278: else
279: return CONST_DOUBLE_LOW (x);
280: }
281:
282: /* Inline block copy. */
283:
284: void
285: expand_movstr (operands)
286: rtx *operands;
287: {
288: rtx dest = operands[0];
289: rtx src = operands[1];
290: int align = INTVAL (operands[3]);
291: int nregs, maxsize;
292: unsigned len;
293: enum machine_mode mode;
294: rtx reg, load, store, prev_store, prev_store_2;
295: int size;
296:
297: /* Decide how many regs to use, depending on load latency, and what
298: size pieces to move, depending on whether machine does unaligned
299: loads and stores efficiently. */
300:
301: if (TARGET_C1)
302: {
303: /* ld.l latency is 4, no alignment problems. */
304: nregs = 3, maxsize = 8;
305: }
306: else if (TARGET_C2)
307: {
308: /* loads are latency 2 if we avoid ld.l not at least word aligned. */
309: if (align >= 4)
310: nregs = 2, maxsize = 8;
311: else
312: nregs = 2, maxsize = 4;
313: }
314: else if (TARGET_C34)
315: {
316: /* latency is 4 if aligned, horrible if not. */
317: nregs = 3, maxsize = align;
318: }
319: else if (TARGET_C38)
320: {
321: /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
322: if (align >= 4)
323: nregs = 2, maxsize = 8;
324: else
325: nregs = 3, maxsize = 8;
326: }
327: else
328: abort ();
329:
330: /* Caller is not necessarily prepared for us to fail in this
331: expansion. So fall back by generating memcpy call here. */
332:
333: if (GET_CODE (operands[2]) != CONST_INT
334: || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
335: {
336: expand_movstr_call (operands);
337: return;
338: }
339:
340: reg = 0;
341: prev_store = prev_store_2 = 0;
342:
343: while (len > 0)
344: {
345: if (len >= 8 && maxsize >= 8)
346: mode = DImode;
347: else if (len >= 4 && maxsize >= 4)
348: mode = SImode;
349: else if (len >= 2 && maxsize >= 2)
350: mode = HImode;
351: else
352: mode = QImode;
353:
354: /* If no temp pseudo to reuse, or not the right mode, make one */
355: if (! reg || GET_MODE (reg) != mode)
356: reg = gen_reg_rtx (mode);
357:
358: /* Get src and dest in the right mode */
359: if (GET_MODE (src) != mode)
360: src = change_address (src, mode, 0),
361: dest = change_address (dest, mode, 0);
362:
363: /* Make load and store patterns for this piece */
364: load = gen_rtx (SET, VOIDmode, reg, src);
365: store = gen_rtx (SET, VOIDmode, dest, reg);
366:
367: /* Emit the load and the store from last time.
368: When we emit a store, we can reuse its temp reg. */
369: emit_insn (load);
370: if (prev_store)
371: {
372: reg = SET_SRC (prev_store);
373: emit_insn (prev_store);
374: }
375: else
376: reg = 0;
377:
378: /* Queue up the store, for next time or the time after that. */
379: if (nregs == 2)
380: prev_store = store;
381: else
382: prev_store = prev_store_2, prev_store_2 = store;
383:
384: /* Advance to next piece. */
385: size = GET_MODE_SIZE (mode);
386: src = adj_offsettable_operand (src, size);
387: dest = adj_offsettable_operand (dest, size);
388: len -= size;
389: }
390:
391: /* Finally, emit the last stores. */
392: if (prev_store)
393: emit_insn (prev_store);
394: if (prev_store_2)
395: emit_insn (prev_store_2);
396: }
397:
398: static void
399: expand_movstr_call (operands)
400: rtx *operands;
401: {
402: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
403: VOIDmode, 3,
404: XEXP (operands[0], 0), Pmode,
405: XEXP (operands[1], 0), Pmode,
406: operands[2], SImode);
407: }
408:
409: #if _IEEE_FLOAT_
410: #define MAX_FLOAT 3.4028234663852886e+38
411: #define MIN_FLOAT 1.1754943508222875e-38
412: #else
413: #define MAX_FLOAT 1.7014117331926443e+38
414: #define MIN_FLOAT 2.9387358770557188e-39
415: #endif
416:
1.1.1.2 root 417: int
418: check_float_value (mode, dp, overflow)
1.1 root 419: enum machine_mode mode;
420: REAL_VALUE_TYPE *dp;
1.1.1.2 root 421: int overflow;
1.1 root 422: {
423: REAL_VALUE_TYPE d = *dp;
424:
1.1.1.2 root 425: if (overflow)
426: {
427: *dp = MAX_FLOAT;
428: return 1;
429: }
430:
1.1 root 431: if (mode == SFmode)
432: {
433: if (d > MAX_FLOAT)
434: {
435: *dp = MAX_FLOAT;
1.1.1.2 root 436: return 1;
1.1 root 437: }
438: else if (d < -MAX_FLOAT)
439: {
440: *dp = -MAX_FLOAT;
1.1.1.2 root 441: return 1;
1.1 root 442: }
443: else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
444: {
445: *dp = 0.0;
1.1.1.2 root 446: return 1;
1.1 root 447: }
448: }
1.1.1.2 root 449:
450: return 0;
1.1 root 451: }
452:
453: /* Output the label at the start of a function.
454: Precede it with the number of formal args so debuggers will have
455: some idea of how many args to print. */
456:
457: void
458: asm_declare_function_name (file, name, decl)
459: FILE *file;
460: char *name;
461: tree decl;
462: {
463: tree parms;
464: int nargs = list_length (DECL_ARGUMENTS (decl));
465:
466: char *p, c;
467: extern char *version_string;
468: static char vers[4];
469: int i;
470:
471: p = version_string;
472: for (i = 0; i < 3; ) {
473: c = *p;
474: if (c - '0' < (unsigned) 10)
475: vers[i++] = c;
476: if (c == 0 || c == ' ')
477: vers[i++] = '0';
478: else
479: p++;
480: }
481: fprintf (file, "\tds.b \"g%s\"\n", vers);
482:
483: if (nargs < 100)
484: fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs);
485: else
486: fprintf (file, "\tds.b \"+00\\0\"\n");
487:
488: ASM_OUTPUT_LABEL (file, name);
489: }
490:
491: /* Print an instruction operand X on file FILE.
492: CODE is the code from the %-spec that requested printing this operand;
493: if `%z3' was used to print operand 3, then CODE is 'z'. */
494: /* Convex codes:
495: %u prints a CONST_DOUBLE's high word
496: %v prints a CONST_DOUBLE's low word
497: %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n.
498: */
499:
500: print_operand (file, x, code)
501: FILE *file;
502: rtx x;
503: char code;
504: {
505: long u[2];
506: REAL_VALUE_TYPE d;
507:
508: switch (GET_CODE (x))
509: {
510: case REG:
511: fprintf (file, "%s", reg_names[REGNO (x)]);
512: break;
513:
514: case MEM:
515: output_address (XEXP (x, 0));
516: break;
517:
518: case CONST_DOUBLE:
519: REAL_VALUE_FROM_CONST_DOUBLE (d, x);
520: switch (GET_MODE (x)) {
521: case DFmode:
522: #if 0 /* doesn't work, produces dfloats */
523: REAL_VALUE_TO_TARGET_DOUBLE (d, u);
524: #else
525: {
526: union { double d; int i[2]; } t;
527: t.d = d;
528: u[0] = t.i[0];
529: u[1] = t.i[1];
530: }
531: #endif
532: if (code == 'u')
533: fprintf (file, "#%#x", u[0]);
534: else if (code == 'v')
535: fprintf (file, "#%#x", u[1]);
536: else
537: outfloat (file, d, "%.17e", "#", "");
538: break;
539: case SFmode:
540: outfloat (file, d, "%.9e", "#", "");
541: break;
542: default:
543: if (code == 'u')
544: fprintf (file, "#%d", CONST_DOUBLE_HIGH (x));
545: else
546: fprintf (file, "#%d", CONST_DOUBLE_LOW (x));
547: }
548: break;
549:
550: default:
551: if (code == 'z')
552: {
553: if (GET_CODE (x) != CONST_INT)
554: abort ();
555: fprintf (file, "#%d", 1 << INTVAL (x));
556: }
557: else
558: {
559: putc ('#', file);
560: output_addr_const (file, x);
561: }
562: }
563: }
564:
565: /* Print a memory operand whose address is X, on file FILE. */
566:
567: print_operand_address (file, addr)
568: FILE *file;
569: rtx addr;
570: {
571: rtx index = 0;
572: rtx offset = 0;
573:
574: if (GET_CODE (addr) == MEM)
575: {
576: fprintf (file, "@");
577: addr = XEXP (addr, 0);
578: }
579:
580: switch (GET_CODE (addr))
581: {
582: case REG:
583: index = addr;
584: break;
585:
586: case PLUS:
587: index = XEXP (addr, 0);
588: if (REG_P (index))
589: offset = XEXP (addr, 1);
590: else
591: {
592: offset = XEXP (addr, 0);
593: index = XEXP (addr, 1);
594: if (! REG_P (index))
595: abort ();
596: }
597: break;
598:
599: default:
600: offset = addr;
601: break;
602: }
603:
604: if (offset)
605: output_addr_const (file, offset);
606:
607: if (index)
608: fprintf (file, "(%s)", reg_names[REGNO (index)]);
609: }
610:
611: /* Output a float to FILE, value VALUE, format FMT, preceded by PFX
612: and followed by SFX. */
613:
614: outfloat (file, value, fmt, pfx, sfx)
615: FILE *file;
616: REAL_VALUE_TYPE value;
617: char *fmt, *pfx, *sfx;
618: {
619: char buf[64];
620: fputs (pfx, file);
621: REAL_VALUE_TO_DECIMAL (value, fmt, buf);
622: fputs (buf, file);
623: fputs (sfx, file);
624: }
625:
626: /* Here during RTL generation of return. If we are at the final return
627: in a function, go through the function and replace pushes with stores
628: into a frame arg block. This is similar to what ACCUMULATE_OUTGOING_ARGS
629: does, but we must index off the frame pointer, not the stack pointer,
630: and the calling sequence does not require the arg block to be at the
631: top of the stack. */
632:
633: replace_arg_pushes ()
634: {
635: /* Doesn't work yet. */
636: }
637:
638: /* Output the insns needed to do a call. operands[] are
639: 0 - MEM, the place to call
640: 1 - CONST_INT, the number of bytes in the arg list
641: 2 - CONST_INT, the number of arguments
642: 3 - CONST_INT, the number of bytes to pop
643: 4 - address of the arg list.
644: */
645:
646: char *
647: output_call (insn, operands)
648: rtx insn, *operands;
649: {
650: if (operands[4] == stack_pointer_rtx)
651: output_asm_insn ("mov sp,ap", operands);
652: else
653: abort ();
654:
655: if (TARGET_ARGCOUNT)
656: output_asm_insn ("pshea %a2", operands);
657:
658: output_asm_insn ("calls %0", operands);
659:
660: output_asm_insn ("ld.w 12(fp),ap", operands);
661:
662: if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx)
663: output_asm_insn ("add.w %3,sp", operands);
664:
665: return "";
666: }
667:
668:
669: /* Here after reloading, before the second scheduling pass. */
670:
671: emit_ap_optimizations ()
672: {
673: /* Removed for now. */
674: }
675:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.