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)
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. */
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.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. */
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
;
62 static rtx frame_argblock
;
63 static int frame_argblock_size
;
64 static rtx
convert_arg_pushes ();
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. */
88 convex_output_function_prologue (file
, size
)
92 size
= ((size
) + 7) & -8;
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. */
106 convex_output_function_epilogue (file
, size
)
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. */
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
;
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 ();
159 #if __convex__ && __GNUC__
161 asm ("mov fp,%0" : "=a" (p
));
170 /* Here to output code for a compare insn. Output nothing, just
171 record the operands and their mode. */
174 output_cmp (operand0
, operand1
, modech
)
175 rtx operand0
, operand1
;
178 cmp_operand0
= operand0
;
179 cmp_operand1
= operand1
;
184 /* Output code for a conditional jump. The preceding instruction
185 is necessarily a compare. Output two instructions, for example
194 output_condjump (label
, cond
, jbr_sense
)
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
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
)
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';
247 operands
[0] = cmp_operand0
;
248 operands
[1] = cmp_operand1
;
253 if (S_REG_P (operands
[1]))
255 else if (A_REG_P (operands
[1]))
260 if (cmp_modech
== 'W' || cmp_modech
== 'H')
261 sprintf (buf
, "jbr%c.%c %%l2", jbr_regch
, jbr_sense
);
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
);
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
)
277 enum machine_mode mode
;
280 if (op
== CONST0_RTX (SFmode
))
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
)
294 switch (GET_CODE (x
))
297 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
298 && INTVAL (XEXP (x
, 1)) < 0)
301 XEXP (x
, 1) = GEN_INT (- INTVAL (XEXP (x
, 1)));
306 return simplify_for_convex (XEXP (x
, 0));
314 /* Routines to separate CONST_DOUBLEs into component parts. */
317 const_double_high_int (x
)
320 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
321 return CONST_DOUBLE_LOW (x
);
323 return CONST_DOUBLE_HIGH (x
);
327 const_double_low_int (x
)
330 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
331 return CONST_DOUBLE_HIGH (x
);
333 return CONST_DOUBLE_LOW (x
);
336 /* Inline block copy. */
339 expand_movstr (operands
)
342 rtx dest
= operands
[0];
343 rtx src
= operands
[1];
344 int align
= INTVAL (operands
[3]);
347 enum machine_mode mode
;
348 rtx reg
, load
, store
, prev_store
, prev_store_2
;
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. */
357 /* ld.l latency is 4, no alignment problems. */
358 nregs
= 3, maxsize
= 8;
362 /* loads are latency 2 if we avoid ld.l not at least word aligned. */
364 nregs
= 2, maxsize
= 8;
366 nregs
= 2, maxsize
= 4;
370 /* latency is 4 if aligned, horrible if not. */
371 nregs
= 3, maxsize
= align
;
375 /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */
377 nregs
= 2, maxsize
= 8;
379 nregs
= 3, maxsize
= 8;
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
);
395 prev_store
= prev_store_2
= 0;
399 if (len
>= 8 && maxsize
>= 8)
401 else if (len
>= 4 && maxsize
>= 4)
403 else if (len
>= 2 && maxsize
>= 2)
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. */
428 reg
= SET_SRC (prev_store
);
429 emit_insn (prev_store
);
434 /* Queue up the store, for next time or the time after that. */
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
);
447 /* Finally, emit the last stores. */
449 emit_insn (prev_store
);
451 emit_insn (prev_store_2
);
455 expand_movstr_call (operands
)
458 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "memcpy"), 0,
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
));
468 #define MAX_FLOAT 3.4028234663852886e+38
469 #define MIN_FLOAT 1.1754943508222875e-38
471 #define MAX_FLOAT 1.7014117331926443e+38
472 #define MIN_FLOAT 2.9387358770557188e-39
476 check_float_value (mode
, dp
, overflow
)
477 enum machine_mode mode
;
481 REAL_VALUE_TYPE d
= *dp
;
496 else if (d
< -MAX_FLOAT
)
501 else if ((d
> 0 && d
< MIN_FLOAT
) || (d
< 0 && d
> -MIN_FLOAT
))
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. */
516 asm_declare_function_name (file
, name
, decl
)
521 int nargs
= list_length (DECL_ARGUMENTS (decl
));
529 for (i
= 0; i
< 3; ) {
531 if (c
- '0' < (unsigned) 10)
533 if (c
== 0 || c
== ' ')
538 fprintf (file
, "\tds.b \"g%s\"\n", vers
);
541 fprintf (file
, "\tds.b \"+%02d\\0\"\n", nargs
);
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'. */
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.
558 print_operand (file
, x
, code
)
566 switch (GET_CODE (x
))
569 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
573 output_address (XEXP (x
, 0));
577 REAL_VALUE_FROM_CONST_DOUBLE (d
, x
);
578 switch (GET_MODE (x
)) {
580 #if 0 /* doesn't work, produces dfloats */
581 REAL_VALUE_TO_TARGET_DOUBLE (d
, u
);
584 union { double d
; int i
[2]; } t
;
591 fprintf (file
, "#%#lx", u
[0]);
592 else if (code
== 'v')
593 fprintf (file
, "#%#lx", u
[1]);
595 outfloat (file
, d
, "%.17e", "#", "");
598 outfloat (file
, d
, "%.9e", "#", "");
602 fprintf (file
, "#%d", CONST_DOUBLE_HIGH (x
));
604 fprintf (file
, "#%d", CONST_DOUBLE_LOW (x
));
611 if (GET_CODE (x
) != CONST_INT
)
613 fprintf (file
, "#%d", 1 << INTVAL (x
));
618 output_addr_const (file
, x
);
623 /* Print a memory operand whose address is X, on file FILE. */
626 print_operand_address (file
, addr
)
633 if (GET_CODE (addr
) == MEM
)
636 addr
= XEXP (addr
, 0);
639 switch (GET_CODE (addr
))
646 index
= XEXP (addr
, 0);
648 offset
= XEXP (addr
, 1);
651 offset
= XEXP (addr
, 0);
652 index
= XEXP (addr
, 1);
664 output_addr_const (file
, offset
);
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. */
674 outfloat (file
, value
, fmt
, pfx
, sfx
)
676 REAL_VALUE_TYPE value
;
677 const char *fmt
, *pfx
, *sfx
;
681 REAL_VALUE_TO_DECIMAL (value
, fmt
, buf
);
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
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.
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
);
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
);
730 /* Here after reloading, before the second scheduling pass. */
733 emit_ap_optimizations ()
735 /* Removed for now. */