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