1 /* Subroutines for insn-output.c for Convex.
2 Copyright (C) 1988, 1993, 1994 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. */
25 #include "hard-reg-set.h"
27 #include "insn-config.h"
28 #include "conditions.h"
29 #include "insn-flags.h"
30 #include "insn-attr.h"
37 /* Tables used in convex.h */
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];
43 /* Target cpu index. */
47 /* Boolean to keep track of whether the current section is .text or not.
48 Used by .align handler in convex.h. */
50 int current_section_is_text;
52 /* Communication between output_compare and output_condjump. */
54 static rtx cmp_operand0, cmp_operand1;
55 static char cmp_modech;
59 static rtx frame_argblock;
60 static int frame_argblock_size;
61 static rtx convert_arg_pushes ();
62 static void expand_movstr_call ();
64 /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */
70 /* Set A and S reg classes. */
71 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
72 if (A_REGNO_P (regno))
74 regno_ok_for_index_p[regno] = 1;
75 regno_reg_class[regno] = INDEX_REGS;
79 regno_ok_for_index_p[regno] = 0;
80 regno_reg_class[regno] = S_REGS;
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;
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;
93 /* Can't index off hard reg -1 == pseudos not assigned */
94 regno_ok_for_index_p[-1] = 0;
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;
101 /* Turn off floating point exception enables in the psw. */
102 psw_disable_float ();
107 #if __convex__ && __GNUC__
109 asm ("mov fp,%0" : "=a" (p));
118 /* Here to output code for a compare insn. Output nothing, just
119 record the operands and their mode. */
122 output_cmp (operand0, operand1, modech)
123 rtx operand0, operand1;
126 cmp_operand0 = operand0;
127 cmp_operand1 = operand1;
132 /* Output code for a conditional jump. The preceding instruction
133 is necessarily a compare. Output two instructions, for example
142 output_condjump (label, cond, jbr_sense)
152 strcpy (cmp_op, cond);
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
159 if (cmp_modech == 'B' || cmp_modech == 'L')
161 cmp_modech = cmp_modech - 'A' + 'a';
162 strcpy (cmp_op, "neg");
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. */
169 else if (cmp_modech == 'W' || cmp_modech == 'H')
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)
176 cmp_modech = cmp_modech - 'A' + 'a';
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. */
183 if (! REG_P (cmp_operand1))
185 operands[0] = cmp_operand1;
186 operands[1] = cmp_operand0;
187 if (cmp_op[0] == 'l')
189 cmp_op[1] ^= 'e' ^ 't';
190 jbr_sense ^= 't' ^ 'f';
195 operands[0] = cmp_operand0;
196 operands[1] = cmp_operand1;
201 if (S_REG_P (operands[1]))
203 else if (A_REG_P (operands[1]))
208 if (cmp_modech == 'W' || cmp_modech == 'H')
209 sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense);
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);
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. */
223 nonmemory_cmpsf_operand (op, mode)
225 enum machine_mode mode;
228 if (op == CONST0_RTX (SFmode))
232 return nonmemory_operand (op, mode);
235 /* Convex /bin/as does not like unary minus in some contexts.
236 Simplify CONST addresses to remove it. */
239 simplify_for_convex (x)
242 switch (GET_CODE (x))
245 if (GET_CODE (XEXP (x, 1)) == CONST_INT
246 && INTVAL (XEXP (x, 1)) < 0)
249 XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1)));
254 return simplify_for_convex (XEXP (x, 0));
260 /* Routines to separate CONST_DOUBLEs into component parts. */
263 const_double_high_int (x)
266 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
267 return CONST_DOUBLE_LOW (x);
269 return CONST_DOUBLE_HIGH (x);
273 const_double_low_int (x)
276 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
277 return CONST_DOUBLE_HIGH (x);
279 return CONST_DOUBLE_LOW (x);
282 /* Inline block copy. */
285 expand_movstr (operands)
288 rtx dest = operands[0];
289 rtx src = operands[1];
290 int align = INTVAL (operands[3]);
293 enum machine_mode mode;
294 rtx reg, load, store, prev_store, prev_store_2;
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. */
303 /* ld.l latency is 4, no alignment problems. */
304 nregs = 3, maxsize = 8;
308 /* loads are latency 2 if we avoid ld.l not at least word aligned. */
310 nregs = 2, maxsize = 8;
312 nregs = 2, maxsize = 4;
316 /* latency is 4 if aligned, horrible if not. */
317 nregs = 3, maxsize = align;
321 /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
323 nregs = 2, maxsize = 8;
325 nregs = 3, maxsize = 8;
330 /* Caller is not necessarily prepared for us to fail in this
331 expansion. So fall back by generating memcpy call here. */
333 if (GET_CODE (operands[2]) != CONST_INT
334 || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize)
336 expand_movstr_call (operands);
341 prev_store = prev_store_2 = 0;
345 if (len >= 8 && maxsize >= 8)
347 else if (len >= 4 && maxsize >= 4)
349 else if (len >= 2 && maxsize >= 2)
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);
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);
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);
367 /* Emit the load and the store from last time.
368 When we emit a store, we can reuse its temp reg. */
372 reg = SET_SRC (prev_store);
373 emit_insn (prev_store);
378 /* Queue up the store, for next time or the time after that. */
382 prev_store = prev_store_2, prev_store_2 = store;
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);
391 /* Finally, emit the last stores. */
393 emit_insn (prev_store);
395 emit_insn (prev_store_2);
399 expand_movstr_call (operands)
402 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
404 XEXP (operands[0], 0), Pmode,
405 XEXP (operands[1], 0), Pmode,
406 operands[2], SImode);
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. */