1 /* Subroutines for insn-output.c for Convex.
2 Copyright (C) 1988, 1993, 1994, 1997 Free Software Foundation, Inc.
4 This file is part of GNU CC.
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)
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.
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, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
26 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-flags.h"
31 #include "insn-attr.h"
35 /* Tables used in convex.h */
37 char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1];
38 enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
39 enum reg_class reg_class_from_letter[256];
41 /* Target cpu index. */
45 /* Boolean to keep track of whether the current section is .text or not.
46 Used by .align handler in convex.h. */
48 int current_section_is_text;
50 /* Communication between output_compare and output_condjump. */
52 static rtx cmp_operand0, cmp_operand1;
53 static char cmp_modech;
57 static rtx frame_argblock;
58 static int frame_argblock_size;
59 static rtx convert_arg_pushes ();
60 static void expand_movstr_call ();
62 /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */
68 /* Set A and S reg classes. */
69 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
70 if (A_REGNO_P (regno))
72 regno_ok_for_index_p[regno] = 1;
73 regno_reg_class[regno] = INDEX_REGS;
77 regno_ok_for_index_p[regno] = 0;
78 regno_reg_class[regno] = S_REGS;
81 /* Can't index off the stack pointer, register 0. */
82 regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0;
83 regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS;
85 /* Can't index off aliases of the stack pointer. */
86 regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1;
87 regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1;
88 regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0;
89 regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0;
91 /* Can't index off hard reg -1 == pseudos not assigned */
92 regno_ok_for_index_p[-1] = 0;
94 /* Set reg class letters */
95 reg_class_from_letter['a'] = A_REGS;
96 reg_class_from_letter['A'] = INDEX_REGS;
97 reg_class_from_letter['d'] = S_REGS;
99 /* Turn off floating point exception enables in the psw. */
100 psw_disable_float ();
105 #if __convex__ && __GNUC__
107 asm ("mov fp,%0" : "=a" (p));
116 /* Here to output code for a compare insn. Output nothing, just
117 record the operands and their mode. */
120 output_cmp (operand0, operand1, modech)
121 rtx operand0, operand1;
124 cmp_operand0 = operand0;
125 cmp_operand1 = operand1;
130 /* Output code for a conditional jump. The preceding instruction
131 is necessarily a compare. Output two instructions, for example
140 output_condjump (label, cond, jbr_sense)
150 strcpy (cmp_op, cond);
152 /* [BL] mean the value is being compared against immediate 0.
153 Use neg.x, which produces the same carry that eq.x #0 would if it
154 existed. In this case operands[1] is a scratch register, not a
157 if (cmp_modech == 'B' || cmp_modech == 'L')
159 cmp_modech = cmp_modech - 'A' + 'a';
160 strcpy (cmp_op, "neg");
163 /* [WH] mean the value being compared resulted from "add.[wh] #-1,rk"
164 when rk was nonnegative -- we can omit equality compares against -1
165 or inequality compares against 0. */
167 else if (cmp_modech == 'W' || cmp_modech == 'H')
169 if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx)
170 jbr_sense ^= 't' ^ 'f';
171 else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx)
174 cmp_modech = cmp_modech - 'A' + 'a';
177 /* Constant must be first; swap operands if necessary.
178 If lt, le, ltu, leu are swapped, change to le, lt, leu, ltu
179 and reverse the sense of the jump. */
181 if (! REG_P (cmp_operand1))
183 operands[0] = cmp_operand1;
184 operands[1] = cmp_operand0;
185 if (cmp_op[0] == 'l')
187 cmp_op[1] ^= 'e' ^ 't';
188 jbr_sense ^= 't' ^ 'f';
193 operands[0] = cmp_operand0;
194 operands[1] = cmp_operand1;
199 if (S_REG_P (operands[1]))
201 else if (A_REG_P (operands[1]))
206 if (cmp_modech == 'W' || cmp_modech == 'H')
207 sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
209 sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2",
210 cmp_op, cmp_modech, jbr_regch, jbr_sense);
211 output_asm_insn (buf, operands);
215 /* Return 1 if OP is valid for cmpsf.
216 In IEEE mode, +/- zero compares are not handled by
217 the immediate versions of eq.s and on some machines, lt.s, and le.s.
218 So disallow 0.0 as the immediate operand of xx.s compares in IEEE mode. */
221 nonmemory_cmpsf_operand (op, mode)
223 enum machine_mode mode;
226 if (op == CONST0_RTX (SFmode))
230 return nonmemory_operand (op, mode);
233 /* Convex /bin/as does not like unary minus in some contexts.
234 Simplify CONST addresses to remove it. */
237 simplify_for_convex (x)
240 switch (GET_CODE (x))
243 if (GET_CODE (XEXP (x, 1)) == CONST_INT
244 && INTVAL (XEXP (x, 1)) < 0)
247 XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
252 return simplify_for_convex (XEXP (x, 0));
258 /* Routines to separate CONST_DOUBLEs into component parts. */
261 const_double_high_int (x)
264 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
265 return CONST_DOUBLE_LOW (x);
267 return CONST_DOUBLE_HIGH (x);
271 const_double_low_int (x)
274 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
275 return CONST_DOUBLE_HIGH (x);
277 return CONST_DOUBLE_LOW (x);
280 /* Inline block copy. */
283 expand_movstr (operands)
286 rtx dest = operands[0];
287 rtx src = operands[1];
288 int align = INTVAL (operands[3]);
291 enum machine_mode mode;
292 rtx reg, load, store, prev_store, prev_store_2;
295 /* Decide how many regs to use, depending on load latency, and what
296 size pieces to move, depending on whether machine does unaligned
297 loads and stores efficiently. */
301 /* ld.l latency is 4, no alignment problems. */
302 nregs = 3, maxsize = 8;
306 /* loads are latency 2 if we avoid ld.l not at least word aligned. */
308 nregs = 2, maxsize = 8;
310 nregs = 2, maxsize = 4;
314 /* latency is 4 if aligned, horrible if not. */
315 nregs = 3, maxsize = align;
319 /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
321 nregs = 2, maxsize = 8;
323 nregs = 3, maxsize = 8;
328 /* Caller is not necessarily prepared for us to fail in this
329 expansion. So fall back by generating memcpy call here. */
331 if (GET_CODE (operands[2]) != CONST_INT
332 || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
334 expand_movstr_call (operands);
339 prev_store = prev_store_2 = 0;
343 if (len >= 8 && maxsize >= 8)
345 else if (len >= 4 && maxsize >= 4)
347 else if (len >= 2 && maxsize >= 2)
352 /* If no temp pseudo to reuse, or not the right mode, make one */
353 if (! reg || GET_MODE (reg) != mode)
354 reg = gen_reg_rtx (mode);
356 /* Get src and dest in the right mode */
357 if (GET_MODE (src) != mode)
358 src = change_address (src, mode, 0),
359 dest = change_address (dest, mode, 0);
361 /* Make load and store patterns for this piece */
362 load = gen_rtx (SET, VOIDmode, reg, src);
363 store = gen_rtx (SET, VOIDmode, dest, reg);
365 /* Emit the load and the store from last time.
366 When we emit a store, we can reuse its temp reg. */
370 reg = SET_SRC (prev_store);
371 emit_insn (prev_store);
376 /* Queue up the store, for next time or the time after that. */
380 prev_store = prev_store_2, prev_store_2 = store;
382 /* Advance to next piece. */
383 size = GET_MODE_SIZE (mode);
384 src = adj_offsettable_operand (src, size);
385 dest = adj_offsettable_operand (dest, size);
389 /* Finally, emit the last stores. */
391 emit_insn (prev_store);
393 emit_insn (prev_store_2);
397 expand_movstr_call (operands)
400 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
402 XEXP (operands[0], 0), Pmode,
403 XEXP (operands[1], 0), Pmode,
404 convert_to_mode (TYPE_MODE (sizetype), operands[2],
405 TREE_UNSIGNED (sizetype)),
406 TYPE_MODE (sizetype));
410 #define MAX_FLOAT 3.4028234663852886e+38
411 #define MIN_FLOAT 1.1754943508222875e-38
413 #define MAX_FLOAT 1.7014117331926443e+38
414 #define MIN_FLOAT 2.9387358770557188e-39
418 check_float_value (mode, dp, overflow)
419 enum machine_mode mode;
423 REAL_VALUE_TYPE d = *dp;
438 else if (d < -MAX_FLOAT)
443 else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
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. */
458 asm_declare_function_name (file, name, decl)
464 int nargs = list_length (DECL_ARGUMENTS (decl));
467 extern char *version_string;
472 for (i = 0; i < 3; ) {
474 if (c - '0' < (unsigned) 10)
476 if (c == 0 || c == ' ')
481 fprintf (file, "\tds.b \"g%s\"\n", vers);
484 fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs);
486 fprintf (file, "\tds.b \"+00\\0\"\n");
488 ASM_OUTPUT_LABEL (file, name);
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'. */
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.
500 print_operand (file, x, code)
508 switch (GET_CODE (x))
511 fprintf (file, "%s", reg_names[REGNO (x)]);
515 output_address (XEXP (x, 0));
519 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
520 switch (GET_MODE (x)) {
522 #if 0 /* doesn't work, produces dfloats */
523 REAL_VALUE_TO_TARGET_DOUBLE (d, u);
526 union { double d; int i[2]; } t;
533 fprintf (file, "#%#x", u[0]);
534 else if (code == 'v')
535 fprintf (file, "#%#x", u[1]);
537 outfloat (file, d, "%.17e", "#", "");
540 outfloat (file, d, "%.9e", "#", "");
544 fprintf (file, "#%d", CONST_DOUBLE_HIGH (x));
546 fprintf (file, "#%d", CONST_DOUBLE_LOW (x));
553 if (GET_CODE (x) != CONST_INT)
555 fprintf (file, "#%d", 1 << INTVAL (x));
560 output_addr_const (file, x);
565 /* Print a memory operand whose address is X, on file FILE. */
567 print_operand_address (file, addr)
574 if (GET_CODE (addr) == MEM)
577 addr = XEXP (addr, 0);
580 switch (GET_CODE (addr))
587 index = XEXP (addr, 0);
589 offset = XEXP (addr, 1);
592 offset = XEXP (addr, 0);
593 index = XEXP (addr, 1);
605 output_addr_const (file, offset);
608 fprintf (file, "(%s)", reg_names[REGNO (index)]);
611 /* Output a float to FILE, value VALUE, format FMT, preceded by PFX
612 and followed by SFX. */
614 outfloat (file, value, fmt, pfx, sfx)
616 REAL_VALUE_TYPE value;
617 char *fmt, *pfx, *sfx;
621 REAL_VALUE_TO_DECIMAL (value, fmt, buf);
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
633 replace_arg_pushes ()
635 /* Doesn't work yet. */
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.
647 output_call (insn, operands)
650 if (operands[4] == stack_pointer_rtx)
651 output_asm_insn ("mov sp,ap", operands);
656 output_asm_insn ("pshea %a2", operands);
658 output_asm_insn ("calls %0", operands);
660 output_asm_insn ("ld.w 12(fp),ap", operands);
662 if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx)
663 output_asm_insn ("add.w %3,sp", operands);
669 /* Here after reloading, before the second scheduling pass. */
671 emit_ap_optimizations ()
673 /* Removed for now. */