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"
36 /* Tables used in convex.h */
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];
42 /* Target cpu index. */
46 /* Boolean to keep track of whether the current section is .text or not.
47 Used by .align handler in convex.h. */
49 int current_section_is_text
;
51 /* Communication between output_compare and output_condjump. */
53 static rtx cmp_operand0
, cmp_operand1
;
54 static char cmp_modech
;
58 static rtx frame_argblock
;
59 static int frame_argblock_size
;
60 static rtx
convert_arg_pushes ();
61 static void expand_movstr_call ();
63 /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */
69 /* Set A and S reg classes. */
70 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
71 if (A_REGNO_P (regno
))
73 regno_ok_for_index_p
[regno
] = 1;
74 regno_reg_class
[regno
] = INDEX_REGS
;
78 regno_ok_for_index_p
[regno
] = 0;
79 regno_reg_class
[regno
] = S_REGS
;
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
;
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;
92 /* Can't index off hard reg -1 == pseudos not assigned */
93 regno_ok_for_index_p
[-1] = 0;
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
;
100 /* Turn off floating point exception enables in the psw. */
101 psw_disable_float ();
106 #if __convex__ && __GNUC__
108 asm ("mov fp,%0" : "=a" (p
));
117 /* Here to output code for a compare insn. Output nothing, just
118 record the operands and their mode. */
121 output_cmp (operand0
, operand1
, modech
)
122 rtx operand0
, operand1
;
125 cmp_operand0
= operand0
;
126 cmp_operand1
= operand1
;
131 /* Output code for a conditional jump. The preceding instruction
132 is necessarily a compare. Output two instructions, for example
141 output_condjump (label
, cond
, jbr_sense
)
151 strcpy (cmp_op
, cond
);
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
158 if (cmp_modech
== 'B' || cmp_modech
== 'L')
160 cmp_modech
= cmp_modech
- 'A' + 'a';
161 strcpy (cmp_op
, "neg");
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. */
168 else if (cmp_modech
== 'W' || cmp_modech
== 'H')
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
)
175 cmp_modech
= cmp_modech
- 'A' + 'a';
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. */
182 if (! REG_P (cmp_operand1
))
184 operands
[0] = cmp_operand1
;
185 operands
[1] = cmp_operand0
;
186 if (cmp_op
[0] == 'l')
188 cmp_op
[1] ^= 'e' ^ 't';
189 jbr_sense
^= 't' ^ 'f';
194 operands
[0] = cmp_operand0
;
195 operands
[1] = cmp_operand1
;
200 if (S_REG_P (operands
[1]))
202 else if (A_REG_P (operands
[1]))
207 if (cmp_modech
== 'W' || cmp_modech
== 'H')
208 sprintf (buf
, "jbr%c.%c %%l2", jbr_regch
, jbr_sense
);
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
);
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. */
222 nonmemory_cmpsf_operand (op
, mode
)
224 enum machine_mode mode
;
227 if (op
== CONST0_RTX (SFmode
))
231 return nonmemory_operand (op
, mode
);
234 /* Convex /bin/as does not like unary minus in some contexts.
235 Simplify CONST addresses to remove it. */
238 simplify_for_convex (x
)
241 switch (GET_CODE (x
))
244 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
245 && INTVAL (XEXP (x
, 1)) < 0)
248 XEXP (x
, 1) = GEN_INT (- INTVAL (XEXP (x
, 1)));
253 return simplify_for_convex (XEXP (x
, 0));
259 /* Routines to separate CONST_DOUBLEs into component parts. */
262 const_double_high_int (x
)
265 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
266 return CONST_DOUBLE_LOW (x
);
268 return CONST_DOUBLE_HIGH (x
);
272 const_double_low_int (x
)
275 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
276 return CONST_DOUBLE_HIGH (x
);
278 return CONST_DOUBLE_LOW (x
);
281 /* Inline block copy. */
284 expand_movstr (operands
)
287 rtx dest
= operands
[0];
288 rtx src
= operands
[1];
289 int align
= INTVAL (operands
[3]);
292 enum machine_mode mode
;
293 rtx reg
, load
, store
, prev_store
, prev_store_2
;
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. */
302 /* ld.l latency is 4, no alignment problems. */
303 nregs
= 3, maxsize
= 8;
307 /* loads are latency 2 if we avoid ld.l not at least word aligned. */
309 nregs
= 2, maxsize
= 8;
311 nregs
= 2, maxsize
= 4;
315 /* latency is 4 if aligned, horrible if not. */
316 nregs
= 3, maxsize
= align
;
320 /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
322 nregs
= 2, maxsize
= 8;
324 nregs
= 3, maxsize
= 8;
329 /* Caller is not necessarily prepared for us to fail in this
330 expansion. So fall back by generating memcpy call here. */
332 if (GET_CODE (operands
[2]) != CONST_INT
333 || (len
= INTVAL (operands
[2])) > (unsigned) 32 * maxsize
)
335 expand_movstr_call (operands
);
340 prev_store
= prev_store_2
= 0;
344 if (len
>= 8 && maxsize
>= 8)
346 else if (len
>= 4 && maxsize
>= 4)
348 else if (len
>= 2 && maxsize
>= 2)
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
);
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);
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
);
366 /* Emit the load and the store from last time.
367 When we emit a store, we can reuse its temp reg. */
371 reg
= SET_SRC (prev_store
);
372 emit_insn (prev_store
);
377 /* Queue up the store, for next time or the time after that. */
381 prev_store
= prev_store_2
, prev_store_2
= store
;
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
);
390 /* Finally, emit the last stores. */
392 emit_insn (prev_store
);
394 emit_insn (prev_store_2
);
398 expand_movstr_call (operands
)
401 emit_library_call (gen_rtx (SYMBOL_REF
, Pmode
, "memcpy"), 0,
403 XEXP (operands
[0], 0), Pmode
,
404 XEXP (operands
[1], 0), Pmode
,
405 convert_to_mode (TYPE_MODE (sizetype
), operands
[2],
406 TREE_UNSIGNED (sizetype
)),
407 TYPE_MODE (sizetype
));
411 #define MAX_FLOAT 3.4028234663852886e+38
412 #define MIN_FLOAT 1.1754943508222875e-38
414 #define MAX_FLOAT 1.7014117331926443e+38
415 #define MIN_FLOAT 2.9387358770557188e-39
419 check_float_value (mode
, dp
, overflow
)
420 enum machine_mode mode
;
424 REAL_VALUE_TYPE d
= *dp
;
439 else if (d
< -MAX_FLOAT
)
444 else if ((d
> 0 && d
< MIN_FLOAT
) || (d
< 0 && d
> -MIN_FLOAT
))
454 /* Output the label at the start of a function.
455 Precede it with the number of formal args so debuggers will have
456 some idea of how many args to print. */
459 asm_declare_function_name (file
, name
, decl
)
465 int nargs
= list_length (DECL_ARGUMENTS (decl
));
468 extern char *version_string
;
473 for (i
= 0; i
< 3; ) {
475 if (c
- '0' < (unsigned) 10)
477 if (c
== 0 || c
== ' ')
482 fprintf (file
, "\tds.b \"g%s\"\n", vers
);
485 fprintf (file
, "\tds.b \"+%02d\\0\"\n", nargs
);
487 fprintf (file
, "\tds.b \"+00\\0\"\n");
489 ASM_OUTPUT_LABEL (file
, name
);
492 /* Print an instruction operand X on file FILE.
493 CODE is the code from the %-spec that requested printing this operand;
494 if `%z3' was used to print operand 3, then CODE is 'z'. */
496 %u prints a CONST_DOUBLE's high word
497 %v prints a CONST_DOUBLE's low word
498 %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n.
501 print_operand (file
, x
, code
)
509 switch (GET_CODE (x
))
512 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
516 output_address (XEXP (x
, 0));
520 REAL_VALUE_FROM_CONST_DOUBLE (d
, x
);
521 switch (GET_MODE (x
)) {
523 #if 0 /* doesn't work, produces dfloats */
524 REAL_VALUE_TO_TARGET_DOUBLE (d
, u
);
527 union { double d
; int i
[2]; } t
;
534 fprintf (file
, "#%#x", u
[0]);
535 else if (code
== 'v')
536 fprintf (file
, "#%#x", u
[1]);
538 outfloat (file
, d
, "%.17e", "#", "");
541 outfloat (file
, d
, "%.9e", "#", "");
545 fprintf (file
, "#%d", CONST_DOUBLE_HIGH (x
));
547 fprintf (file
, "#%d", CONST_DOUBLE_LOW (x
));
554 if (GET_CODE (x
) != CONST_INT
)
556 fprintf (file
, "#%d", 1 << INTVAL (x
));
561 output_addr_const (file
, x
);
566 /* Print a memory operand whose address is X, on file FILE. */
568 print_operand_address (file
, addr
)
575 if (GET_CODE (addr
) == MEM
)
578 addr
= XEXP (addr
, 0);
581 switch (GET_CODE (addr
))
588 index
= XEXP (addr
, 0);
590 offset
= XEXP (addr
, 1);
593 offset
= XEXP (addr
, 0);
594 index
= XEXP (addr
, 1);
606 output_addr_const (file
, offset
);
609 fprintf (file
, "(%s)", reg_names
[REGNO (index
)]);
612 /* Output a float to FILE, value VALUE, format FMT, preceded by PFX
613 and followed by SFX. */
615 outfloat (file
, value
, fmt
, pfx
, sfx
)
617 REAL_VALUE_TYPE value
;
618 char *fmt
, *pfx
, *sfx
;
622 REAL_VALUE_TO_DECIMAL (value
, fmt
, buf
);
627 /* Here during RTL generation of return. If we are at the final return
628 in a function, go through the function and replace pushes with stores
629 into a frame arg block. This is similar to what ACCUMULATE_OUTGOING_ARGS
630 does, but we must index off the frame pointer, not the stack pointer,
631 and the calling sequence does not require the arg block to be at the
634 replace_arg_pushes ()
636 /* Doesn't work yet. */
639 /* Output the insns needed to do a call. operands[] are
640 0 - MEM, the place to call
641 1 - CONST_INT, the number of bytes in the arg list
642 2 - CONST_INT, the number of arguments
643 3 - CONST_INT, the number of bytes to pop
644 4 - address of the arg list.
648 output_call (insn
, operands
)
651 if (operands
[4] == stack_pointer_rtx
)
652 output_asm_insn ("mov sp,ap", operands
);
657 output_asm_insn ("pshea %a2", operands
);
659 output_asm_insn ("calls %0", operands
);
661 output_asm_insn ("ld.w 12(fp),ap", operands
);
663 if (operands
[4] == stack_pointer_rtx
&& operands
[3] != const0_rtx
)
664 output_asm_insn ("add.w %3,sp", operands
);
670 /* Here after reloading, before the second scheduling pass. */
672 emit_ap_optimizations ()
674 /* Removed for now. */