* target.h (targetm): Rename global from "target", so as not to
[official-gcc.git] / gcc / config / convex / convex.c
bloba0e0987b88e700227a0e9d40a4a8e091bb9c8d5b
1 /* Subroutines for insn-output.c for Convex.
2 Copyright (C) 1988, 1993, 1994, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU CC.
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.
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.
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, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include "config.h"
23 #include "system.h"
24 #include "tree.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.h"
32 #include "output.h"
33 #include "function.h"
34 #include "expr.h"
35 #include "tm_p.h"
36 #include "target.h"
37 #include "target-def.h"
39 /* Tables used in convex.h */
41 char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1];
42 enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
43 enum reg_class reg_class_from_letter[256];
45 /* Target cpu index. */
47 int target_cpu;
49 /* Boolean to keep track of whether the current section is .text or not.
50 Used by .align handler in convex.h. */
52 int current_section_is_text;
54 /* Communication between output_compare and output_condjump. */
56 static rtx cmp_operand0, cmp_operand1;
57 static char cmp_modech;
59 /* Forwards */
61 #if 0
62 static rtx frame_argblock;
63 static int frame_argblock_size;
64 static rtx convert_arg_pushes ();
65 #endif
66 static void expand_movstr_call PARAMS ((rtx *));
67 static void convex_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
68 static void convex_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
70 /* Initialize the GCC target structure. */
71 #undef TARGET_ASM_FUNCTION_PROLOGUE
72 #define TARGET_ASM_FUNCTION_PROLOGUE convex_output_function_prologue
73 #undef TARGET_ASM_FUNCTION_EPILOGUE
74 #define TARGET_ASM_FUNCTION_EPILOGUE convex_output_function_epilogue
76 struct gcc_target targetm = TARGET_INITIALIZER;
78 /* Generate the assembly code for function entry. FILE is a stdio
79 stream to output the code to. SIZE is an int: how many units of
80 temporary storage to allocate.
82 Refer to the array `regs_ever_live' to determine which registers to
83 save; `regs_ever_live[I]' is nonzero if register number I is ever
84 used in the function. This function is responsible for knowing
85 which registers should not be saved even if used. */
87 static void
88 convex_output_function_prologue (file, size)
89 FILE *file;
90 HOST_WIDE_INT size;
92 size = ((size) + 7) & -8;
93 if (size)
94 fprintf (file, "\tsub.w #%d,sp\n", size);
97 /* This function generates the assembly code for function exit.
98 Args are as for output_function_prologue ().
100 The function epilogue should not depend on the current stack
101 pointer! It should use the frame pointer only. This is mandatory
102 because of alloca; we also take advantage of it to omit stack
103 adjustments before returning. */
105 static void
106 convex_output_function_epilogue (file, size)
107 FILE *file;
108 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
110 /* Follow function with a zero to stop c34 icache prefetching. */
111 fprintf (file, "\tds.h 0\n");
114 /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */
116 void
117 init_convex ()
119 int regno;
121 /* Set A and S reg classes. */
122 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
123 if (A_REGNO_P (regno))
125 regno_ok_for_index_p[regno] = 1;
126 regno_reg_class[regno] = INDEX_REGS;
128 else
130 regno_ok_for_index_p[regno] = 0;
131 regno_reg_class[regno] = S_REGS;
134 /* Can't index off the stack pointer, register 0. */
135 regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0;
136 regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS;
138 /* Can't index off aliases of the stack pointer. */
139 regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1;
140 regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1;
141 regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0;
142 regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0;
144 /* Can't index off hard reg -1 == pseudos not assigned */
145 regno_ok_for_index_p[-1] = 0;
147 /* Set reg class letters */
148 reg_class_from_letter['a'] = A_REGS;
149 reg_class_from_letter['A'] = INDEX_REGS;
150 reg_class_from_letter['d'] = S_REGS;
152 /* Turn off floating point exception enables in the psw. */
153 psw_disable_float ();
156 void
157 psw_disable_float ()
159 #if __convex__ && __GNUC__
160 register int *p;
161 asm ("mov fp,%0" : "=a" (p));
162 while (p)
164 p[1] &= ~0x1000c400;
165 p = (int *) p[2];
167 #endif
170 /* Here to output code for a compare insn. Output nothing, just
171 record the operands and their mode. */
173 const char *
174 output_cmp (operand0, operand1, modech)
175 rtx operand0, operand1;
176 int modech;
178 cmp_operand0 = operand0;
179 cmp_operand1 = operand1;
180 cmp_modech = modech;
181 return "";
184 /* Output code for a conditional jump. The preceding instruction
185 is necessarily a compare. Output two instructions, for example
186 eq.w a1,a2
187 jbra.t L5
189 (cmpsi a1 a2)
190 (beq L5)
193 const char *
194 output_condjump (label, cond, jbr_sense)
195 rtx label;
196 const char *cond;
197 int jbr_sense;
199 rtx operands[3];
200 char cmp_op[4];
201 char buf[80];
202 char jbr_regch;
204 strcpy (cmp_op, cond);
206 /* [BL] mean the value is being compared against immediate 0.
207 Use neg.x, which produces the same carry that eq.x #0 would if it
208 existed. In this case operands[1] is a scratch register, not a
209 compare operand. */
211 if (cmp_modech == 'B' || cmp_modech == 'L')
213 cmp_modech = cmp_modech - 'A' + 'a';
214 strcpy (cmp_op, "neg");
217 /* [WH] mean the value being compared resulted from "add.[wh] #-1,rk"
218 when rk was nonnegative -- we can omit equality compares against -1
219 or inequality compares against 0. */
221 else if (cmp_modech == 'W' || cmp_modech == 'H')
223 if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx)
224 jbr_sense ^= 't' ^ 'f';
225 else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx)
227 else
228 cmp_modech = cmp_modech - 'A' + 'a';
231 /* Constant must be first; swap operands if necessary.
232 If lt, le, ltu, leu are swapped, change to le, lt, leu, ltu
233 and reverse the sense of the jump. */
235 if (! REG_P (cmp_operand1))
237 operands[0] = cmp_operand1;
238 operands[1] = cmp_operand0;
239 if (cmp_op[0] == 'l')
241 cmp_op[1] ^= 'e' ^ 't';
242 jbr_sense ^= 't' ^ 'f';
245 else
247 operands[0] = cmp_operand0;
248 operands[1] = cmp_operand1;
251 operands[2] = label;
253 if (S_REG_P (operands[1]))
254 jbr_regch = 's';
255 else if (A_REG_P (operands[1]))
256 jbr_regch = 'a';
257 else
258 abort ();
260 if (cmp_modech == 'W' || cmp_modech == 'H')
261 sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
262 else
263 sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2",
264 cmp_op, cmp_modech, jbr_regch, jbr_sense);
265 output_asm_insn (buf, operands);
266 return "";
269 /* Return 1 if OP is valid for cmpsf.
270 In IEEE mode, +/- zero compares are not handled by
271 the immediate versions of eq.s and on some machines, lt.s, and le.s.
272 So disallow 0.0 as the immediate operand of xx.s compares in IEEE mode. */
275 nonmemory_cmpsf_operand (op, mode)
276 rtx op;
277 enum machine_mode mode;
279 #if _IEEE_FLOAT_
280 if (op == CONST0_RTX (SFmode))
281 return 0;
282 #endif
284 return nonmemory_operand (op, mode);
287 /* Convex /bin/as does not like unary minus in some contexts.
288 Simplify CONST addresses to remove it. */
291 simplify_for_convex (x)
292 rtx x;
294 switch (GET_CODE (x))
296 case MINUS:
297 if (GET_CODE (XEXP (x, 1)) == CONST_INT
298 && INTVAL (XEXP (x, 1)) < 0)
300 PUT_CODE (x, PLUS);
301 XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
303 break;
305 case CONST:
306 return simplify_for_convex (XEXP (x, 0));
307 default:
308 break;
311 return x;
314 /* Routines to separate CONST_DOUBLEs into component parts. */
317 const_double_high_int (x)
318 rtx x;
320 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
321 return CONST_DOUBLE_LOW (x);
322 else
323 return CONST_DOUBLE_HIGH (x);
327 const_double_low_int (x)
328 rtx x;
330 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
331 return CONST_DOUBLE_HIGH (x);
332 else
333 return CONST_DOUBLE_LOW (x);
336 /* Inline block copy. */
338 void
339 expand_movstr (operands)
340 rtx *operands;
342 rtx dest = operands[0];
343 rtx src = operands[1];
344 int align = INTVAL (operands[3]);
345 int nregs, maxsize;
346 unsigned len;
347 enum machine_mode mode;
348 rtx reg, load, store, prev_store, prev_store_2;
349 int size;
351 /* Decide how many regs to use, depending on load latency, and what
352 size pieces to move, depending on whether machine does unaligned
353 loads and stores efficiently. */
355 if (TARGET_C1)
357 /* ld.l latency is 4, no alignment problems. */
358 nregs = 3, maxsize = 8;
360 else if (TARGET_C2)
362 /* loads are latency 2 if we avoid ld.l not at least word aligned. */
363 if (align >= 4)
364 nregs = 2, maxsize = 8;
365 else
366 nregs = 2, maxsize = 4;
368 else if (TARGET_C34)
370 /* latency is 4 if aligned, horrible if not. */
371 nregs = 3, maxsize = align;
373 else if (TARGET_C38)
375 /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
376 if (align >= 4)
377 nregs = 2, maxsize = 8;
378 else
379 nregs = 3, maxsize = 8;
381 else
382 abort ();
384 /* Caller is not necessarily prepared for us to fail in this
385 expansion. So fall back by generating memcpy call here. */
387 if (GET_CODE (operands[2]) != CONST_INT
388 || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
390 expand_movstr_call (operands);
391 return;
394 reg = 0;
395 prev_store = prev_store_2 = 0;
397 while (len > 0)
399 if (len >= 8 && maxsize >= 8)
400 mode = DImode;
401 else if (len >= 4 && maxsize >= 4)
402 mode = SImode;
403 else if (len >= 2 && maxsize >= 2)
404 mode = HImode;
405 else
406 mode = QImode;
408 /* If no temp pseudo to reuse, or not the right mode, make one */
409 if (! reg || GET_MODE (reg) != mode)
410 reg = gen_reg_rtx (mode);
412 /* Get src and dest in the right mode */
413 if (GET_MODE (src) != mode)
415 src = adjust_address (src, mode, 0);
416 dest = adjust_address (dest, mode, 0);
419 /* Make load and store patterns for this piece */
420 load = gen_rtx_SET (VOIDmode, reg, src);
421 store = gen_rtx_SET (VOIDmode, dest, reg);
423 /* Emit the load and the store from last time.
424 When we emit a store, we can reuse its temp reg. */
425 emit_insn (load);
426 if (prev_store)
428 reg = SET_SRC (prev_store);
429 emit_insn (prev_store);
431 else
432 reg = 0;
434 /* Queue up the store, for next time or the time after that. */
435 if (nregs == 2)
436 prev_store = store;
437 else
438 prev_store = prev_store_2, prev_store_2 = store;
440 /* Advance to next piece. */
441 size = GET_MODE_SIZE (mode);
442 src = adj_offsettable_operand (src, size);
443 dest = adj_offsettable_operand (dest, size);
444 len -= size;
447 /* Finally, emit the last stores. */
448 if (prev_store)
449 emit_insn (prev_store);
450 if (prev_store_2)
451 emit_insn (prev_store_2);
454 static void
455 expand_movstr_call (operands)
456 rtx *operands;
458 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,
459 VOIDmode, 3,
460 XEXP (operands[0], 0), Pmode,
461 XEXP (operands[1], 0), Pmode,
462 convert_to_mode (TYPE_MODE (sizetype), operands[2],
463 TREE_UNSIGNED (sizetype)),
464 TYPE_MODE (sizetype));
467 #if _IEEE_FLOAT_
468 #define MAX_FLOAT 3.4028234663852886e+38
469 #define MIN_FLOAT 1.1754943508222875e-38
470 #else
471 #define MAX_FLOAT 1.7014117331926443e+38
472 #define MIN_FLOAT 2.9387358770557188e-39
473 #endif
476 check_float_value (mode, dp, overflow)
477 enum machine_mode mode;
478 REAL_VALUE_TYPE *dp;
479 int overflow;
481 REAL_VALUE_TYPE d = *dp;
483 if (overflow)
485 *dp = MAX_FLOAT;
486 return 1;
489 if (mode == SFmode)
491 if (d > MAX_FLOAT)
493 *dp = MAX_FLOAT;
494 return 1;
496 else if (d < -MAX_FLOAT)
498 *dp = -MAX_FLOAT;
499 return 1;
501 else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
503 *dp = 0.0;
504 return 1;
508 return 0;
511 /* Output the label at the start of a function.
512 Precede it with the number of formal args so debuggers will have
513 some idea of how many args to print. */
515 void
516 asm_declare_function_name (file, name, decl)
517 FILE *file;
518 const char *name;
519 tree decl;
521 int nargs = list_length (DECL_ARGUMENTS (decl));
523 const char *p;
524 char c;
525 static char vers[4];
526 int i;
528 p = version_string;
529 for (i = 0; i < 3; ) {
530 c = *p;
531 if (c - '0' < (unsigned) 10)
532 vers[i++] = c;
533 if (c == 0 || c == ' ')
534 vers[i++] = '0';
535 else
536 p++;
538 fprintf (file, "\tds.b \"g%s\"\n", vers);
540 if (nargs < 100)
541 fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs);
542 else
543 fprintf (file, "\tds.b \"+00\\0\"\n");
545 ASM_OUTPUT_LABEL (file, name);
548 /* Print an instruction operand X on file FILE.
549 CODE is the code from the %-spec that requested printing this operand;
550 if `%z3' was used to print operand 3, then CODE is 'z'. */
551 /* Convex codes:
552 %u prints a CONST_DOUBLE's high word
553 %v prints a CONST_DOUBLE's low word
554 %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n.
557 void
558 print_operand (file, x, code)
559 FILE *file;
560 rtx x;
561 int code;
563 long u[2];
564 REAL_VALUE_TYPE d;
566 switch (GET_CODE (x))
568 case REG:
569 fprintf (file, "%s", reg_names[REGNO (x)]);
570 break;
572 case MEM:
573 output_address (XEXP (x, 0));
574 break;
576 case CONST_DOUBLE:
577 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
578 switch (GET_MODE (x)) {
579 case DFmode:
580 #if 0 /* doesn't work, produces dfloats */
581 REAL_VALUE_TO_TARGET_DOUBLE (d, u);
582 #else
584 union { double d; int i[2]; } t;
585 t.d = d;
586 u[0] = t.i[0];
587 u[1] = t.i[1];
589 #endif
590 if (code == 'u')
591 fprintf (file, "#%#lx", u[0]);
592 else if (code == 'v')
593 fprintf (file, "#%#lx", u[1]);
594 else
595 outfloat (file, d, "%.17e", "#", "");
596 break;
597 case SFmode:
598 outfloat (file, d, "%.9e", "#", "");
599 break;
600 default:
601 if (code == 'u')
602 fprintf (file, "#%d", CONST_DOUBLE_HIGH (x));
603 else
604 fprintf (file, "#%d", CONST_DOUBLE_LOW (x));
606 break;
608 default:
609 if (code == 'z')
611 if (GET_CODE (x) != CONST_INT)
612 abort ();
613 fprintf (file, "#%d", 1 << INTVAL (x));
615 else
617 putc ('#', file);
618 output_addr_const (file, x);
623 /* Print a memory operand whose address is X, on file FILE. */
625 void
626 print_operand_address (file, addr)
627 FILE *file;
628 rtx addr;
630 rtx index = 0;
631 rtx offset = 0;
633 if (GET_CODE (addr) == MEM)
635 fprintf (file, "@");
636 addr = XEXP (addr, 0);
639 switch (GET_CODE (addr))
641 case REG:
642 index = addr;
643 break;
645 case PLUS:
646 index = XEXP (addr, 0);
647 if (REG_P (index))
648 offset = XEXP (addr, 1);
649 else
651 offset = XEXP (addr, 0);
652 index = XEXP (addr, 1);
653 if (! REG_P (index))
654 abort ();
656 break;
658 default:
659 offset = addr;
660 break;
663 if (offset)
664 output_addr_const (file, offset);
666 if (index)
667 fprintf (file, "(%s)", reg_names[REGNO (index)]);
670 /* Output a float to FILE, value VALUE, format FMT, preceded by PFX
671 and followed by SFX. */
673 void
674 outfloat (file, value, fmt, pfx, sfx)
675 FILE *file;
676 REAL_VALUE_TYPE value;
677 const char *fmt, *pfx, *sfx;
679 char buf[64];
680 fputs (pfx, file);
681 REAL_VALUE_TO_DECIMAL (value, fmt, buf);
682 fputs (buf, file);
683 fputs (sfx, file);
686 /* Here during RTL generation of return. If we are at the final return
687 in a function, go through the function and replace pushes with stores
688 into a frame arg block. This is similar to what ACCUMULATE_OUTGOING_ARGS
689 does, but we must index off the frame pointer, not the stack pointer,
690 and the calling sequence does not require the arg block to be at the
691 top of the stack. */
693 void
694 replace_arg_pushes ()
696 /* Doesn't work yet. */
699 /* Output the insns needed to do a call. operands[] are
700 0 - MEM, the place to call
701 1 - CONST_INT, the number of bytes in the arg list
702 2 - CONST_INT, the number of arguments
703 3 - CONST_INT, the number of bytes to pop
704 4 - address of the arg list.
707 const char *
708 output_call (insn, operands)
709 rtx insn ATTRIBUTE_UNUSED, *operands;
711 if (operands[4] == stack_pointer_rtx)
712 output_asm_insn ("mov sp,ap", operands);
713 else
714 abort ();
716 if (TARGET_ARGCOUNT)
717 output_asm_insn ("pshea %a2", operands);
719 output_asm_insn ("calls %0", operands);
721 output_asm_insn ("ld.w 12(fp),ap", operands);
723 if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx)
724 output_asm_insn ("add.w %3,sp", operands);
726 return "";
730 /* Here after reloading, before the second scheduling pass. */
732 void
733 emit_ap_optimizations ()
735 /* Removed for now. */