]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/crx/crx.c
host-hpux.c: Change copyright header to refer to version 3 of the GNU General Public...
[thirdparty/gcc.git] / gcc / config / crx / crx.c
CommitLineData
db869733
PW
1/* Output routines for GCC for CRX.
2 Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
2f83c7d6 3 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
db869733
PW
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
2f83c7d6 9 by the Free Software Foundation; either version 3, or (at your
db869733
PW
10 option) any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
2f83c7d6
NC
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
db869733
PW
20
21/*****************************************************************************/
22/* HEADER INCLUDES */
23/*****************************************************************************/
24
25#include "config.h"
26#include "system.h"
27#include "coretypes.h"
28#include "tm.h"
29#include "rtl.h"
30#include "tree.h"
31#include "tm_p.h"
32#include "regs.h"
33#include "hard-reg-set.h"
34#include "real.h"
35#include "insn-config.h"
36#include "conditions.h"
37#include "output.h"
38#include "insn-codes.h"
39#include "insn-attr.h"
40#include "flags.h"
41#include "except.h"
42#include "function.h"
43#include "recog.h"
44#include "expr.h"
45#include "optabs.h"
46#include "toplev.h"
47#include "basic-block.h"
48#include "target.h"
49#include "target-def.h"
50
51/*****************************************************************************/
52/* DEFINITIONS */
53/*****************************************************************************/
54
55/* Maximum number of register used for passing parameters. */
55d61dba 56#define MAX_REG_FOR_PASSING_ARGS 6
db869733
PW
57
58/* Minimum number register used for passing parameters. */
59#define MIN_REG_FOR_PASSING_ARGS 2
60
61/* The maximum count of words supported in the assembly of the architecture in
62 * a push/pop instruction. */
63#define MAX_COUNT 8
64
65/* Predicate is true if the current function is a 'noreturn' function, i.e. it
66 * is qualified as volatile. */
e95cfa3b 67#define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl))
db869733 68
e95cfa3b 69/* The following macros are used in crx_decompose_address () */
db869733 70
e95cfa3b
PW
71/* Returns the factor of a scaled index address or -1 if invalid. */
72#define SCALE_FOR_INDEX_P(X) \
73 (GET_CODE (X) == CONST_INT ? \
74 (INTVAL (X) == 1 ? 1 : \
75 INTVAL (X) == 2 ? 2 : \
76 INTVAL (X) == 4 ? 4 : \
77 INTVAL (X) == 8 ? 8 : \
78 -1) : \
79 -1)
db869733
PW
80
81/* Nonzero if the rtx X is a signed const int of n bits */
82#define RTX_SIGNED_INT_FITS_N_BITS(X,n) \
e95cfa3b
PW
83 ((GET_CODE (X) == CONST_INT \
84 && SIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
db869733 85
569b7f6a 86/* Nonzero if the rtx X is an unsigned const int of n bits. */
e95cfa3b
PW
87#define RTX_UNSIGNED_INT_FITS_N_BITS(X, n) \
88 ((GET_CODE (X) == CONST_INT \
89 && UNSIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
db869733
PW
90
91/*****************************************************************************/
92/* STATIC VARIABLES */
93/*****************************************************************************/
94
a4d05547 95/* Nonzero if the last param processed is passed in a register. */
db869733
PW
96static int last_parm_in_reg;
97
98/* Will hold the number of the last register the prologue saves, -1 if no
99 * register is saved. */
100static int last_reg_to_save;
101
102/* Each object in the array is a register number. Mark 1 for registers that
103 * need to be saved. */
104static int save_regs[FIRST_PSEUDO_REGISTER];
105
106/* Number of bytes saved on the stack for non-scratch registers */
107static int sum_regs = 0;
108
109/* Number of bytes saved on the stack for local variables. */
110static int local_vars_size;
111
112/* The sum of 2 sizes: locals vars and padding byte for saving the registers.
e95cfa3b 113 * Used in expand_prologue () and expand_epilogue (). */
db869733
PW
114static int size_for_adjusting_sp;
115
116/* In case of a POST_INC or POST_DEC memory reference, we must report the mode
117 * of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */
118static enum machine_mode output_memory_reference_mode;
119
120/*****************************************************************************/
121/* GLOBAL VARIABLES */
122/*****************************************************************************/
123
124/* Table of machine attributes. */
125const struct attribute_spec crx_attribute_table[];
126
127/* Test and compare insns use these globals to generate branch insns. */
128rtx crx_compare_op0 = NULL_RTX;
129rtx crx_compare_op1 = NULL_RTX;
130
131/*****************************************************************************/
132/* TARGETM FUNCTION PROTOTYPES */
133/*****************************************************************************/
134
135static bool crx_fixed_condition_code_regs (unsigned int *, unsigned int *);
136static rtx crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
137 int incoming ATTRIBUTE_UNUSED);
138static bool crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED);
e95cfa3b 139static int crx_address_cost (rtx);
db869733
PW
140
141/*****************************************************************************/
142/* STACK LAYOUT AND CALLING CONVENTIONS */
143/*****************************************************************************/
144
145#undef TARGET_FIXED_CONDITION_CODE_REGS
146#define TARGET_FIXED_CONDITION_CODE_REGS crx_fixed_condition_code_regs
147
148#undef TARGET_STRUCT_VALUE_RTX
149#define TARGET_STRUCT_VALUE_RTX crx_struct_value_rtx
150
151#undef TARGET_RETURN_IN_MEMORY
152#define TARGET_RETURN_IN_MEMORY crx_return_in_memory
153
e95cfa3b
PW
154/*****************************************************************************/
155/* RELATIVE COSTS OF OPERATIONS */
156/*****************************************************************************/
157
158#undef TARGET_ADDRESS_COST
159#define TARGET_ADDRESS_COST crx_address_cost
160
db869733
PW
161/*****************************************************************************/
162/* TARGET-SPECIFIC USES OF `__attribute__' */
163/*****************************************************************************/
164
165#undef TARGET_ATTRIBUTE_TABLE
166#define TARGET_ATTRIBUTE_TABLE crx_attribute_table
167
168const struct attribute_spec crx_attribute_table[] = {
169 /* ISRs have special prologue and epilogue requirements. */
170 {"interrupt", 0, 0, false, true, true, NULL},
171 {NULL, 0, 0, false, false, false, NULL}
172};
173
174
175/* Initialize 'targetm' variable which contains pointers to functions and data
176 * relating to the target machine. */
177
178struct gcc_target targetm = TARGET_INITIALIZER;
179
180
181/*****************************************************************************/
182/* TARGET HOOK IMPLEMENTATIONS */
183/*****************************************************************************/
184
185/* Return the fixed registers used for condition codes. */
186
187static bool
188crx_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
189{
190 *p1 = CC_REGNUM;
191 *p2 = INVALID_REGNUM;
192 return true;
193}
194
195/* Implements hook TARGET_STRUCT_VALUE_RTX. */
196
197static rtx
198crx_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
199 int incoming ATTRIBUTE_UNUSED)
200{
201 return gen_rtx_REG (Pmode, CRX_STRUCT_VALUE_REGNUM);
202}
203
204/* Implements hook TARGET_RETURN_IN_MEMORY. */
205
206static bool
207crx_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
208{
209 if (TYPE_MODE (type) == BLKmode)
210 {
211 HOST_WIDE_INT size = int_size_in_bytes (type);
212 return (size == -1 || size > 8);
213 }
214 else
215 return false;
216}
217
218
219/*****************************************************************************/
220/* MACRO IMPLEMENTATIONS */
221/*****************************************************************************/
222
223/* STACK LAYOUT AND CALLING CONVENTIONS ROUTINES */
224/* --------------------------------------------- */
225
226/* Return nonzero if the current function being compiled is an interrupt
227 * function as specified by the "interrupt" attribute. */
228
229int
230crx_interrupt_function_p (void)
231{
232 tree attributes;
233
234 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
235 return lookup_attribute ("interrupt", attributes) != NULL_TREE;
236}
237
238/* Compute values for the array save_regs and the variable sum_regs. The index
239 * of save_regs is numbers of register, each will get 1 if we need to save it
240 * in the current function, 0 if not. sum_regs is the total sum of the
241 * registers being saved. */
242
243static void
244crx_compute_save_regs (void)
245{
246 unsigned int regno;
247
248 /* initialize here so in case the function is no-return it will be -1. */
249 last_reg_to_save = -1;
250
251 /* No need to save any registers if the function never returns. */
252 if (FUNC_IS_NORETURN_P (current_function_decl))
253 return;
254
255 /* Initialize the number of bytes to be saved. */
256 sum_regs = 0;
257
258 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
259 {
260 if (fixed_regs[regno])
261 {
262 save_regs[regno] = 0;
263 continue;
264 }
265
266 /* If this reg is used and not call-used (except RA), save it. */
e95cfa3b 267 if (crx_interrupt_function_p ())
db869733
PW
268 {
269 if (!current_function_is_leaf && call_used_regs[regno])
270 /* this is a volatile reg in a non-leaf interrupt routine - save it
271 * for the sake of its sons. */
272 save_regs[regno] = 1;
273
6fb5fa3c 274 else if (df_regs_ever_live_p (regno))
db869733
PW
275 /* This reg is used - save it. */
276 save_regs[regno] = 1;
277 else
278 /* This reg is not used, and is not a volatile - don't save. */
279 save_regs[regno] = 0;
280 }
281 else
282 {
283 /* If this reg is used and not call-used (except RA), save it. */
6fb5fa3c 284 if (df_regs_ever_live_p (regno)
db869733
PW
285 && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM))
286 save_regs[regno] = 1;
287 else
288 save_regs[regno] = 0;
289 }
290 }
291
292 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
293 if (save_regs[regno] == 1)
294 {
295 last_reg_to_save = regno;
296 sum_regs += UNITS_PER_WORD;
297 }
298}
299
300/* Compute the size of the local area and the size to be adjusted by the
301 * prologue and epilogue. */
302
303static void
304crx_compute_frame (void)
305{
306 /* For aligning the local variables. */
307 int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
308 int padding_locals;
309
310 /* Padding needed for each element of the frame. */
311 local_vars_size = get_frame_size ();
312
313 /* Align to the stack alignment. */
314 padding_locals = local_vars_size % stack_alignment;
315 if (padding_locals)
316 padding_locals = stack_alignment - padding_locals;
317
318 local_vars_size += padding_locals;
319
320 size_for_adjusting_sp = local_vars_size + (ACCUMULATE_OUTGOING_ARGS ?
321 current_function_outgoing_args_size : 0);
322}
323
324/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */
325
326int
327crx_initial_elimination_offset (int from, int to)
328{
329 /* Compute this since we need to use sum_regs. */
330 crx_compute_save_regs ();
331
332 /* Compute this since we need to use local_vars_size. */
333 crx_compute_frame ();
334
335 if ((from) == FRAME_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM)
336 return (ACCUMULATE_OUTGOING_ARGS ?
337 current_function_outgoing_args_size : 0);
338 else if ((from) == ARG_POINTER_REGNUM && (to) == FRAME_POINTER_REGNUM)
339 return (sum_regs + local_vars_size);
340 else if ((from) == ARG_POINTER_REGNUM && (to) == STACK_POINTER_REGNUM)
341 return (sum_regs + local_vars_size +
342 (ACCUMULATE_OUTGOING_ARGS ?
343 current_function_outgoing_args_size : 0));
344 else
345 abort ();
346}
347
348/* REGISTER USAGE */
349/* -------------- */
350
351/* Return the class number of the smallest class containing reg number REGNO.
352 * This could be a conditional expression or could index an array. */
353
354enum reg_class
355crx_regno_reg_class (int regno)
356{
357 if (regno >= 0 && regno < SP_REGNUM)
358 return NOSP_REGS;
359
e95cfa3b
PW
360 if (regno == SP_REGNUM)
361 return GENERAL_REGS;
db869733 362
e95cfa3b
PW
363 if (regno == LO_REGNUM)
364 return LO_REGS;
365 if (regno == HI_REGNUM)
366 return HI_REGS;
db869733
PW
367
368 return NO_REGS;
369}
370
371/* Transfer between HILO_REGS and memory via secondary reloading. */
372
373enum reg_class
374crx_secondary_reload_class (enum reg_class class,
375 enum machine_mode mode ATTRIBUTE_UNUSED,
376 rtx x ATTRIBUTE_UNUSED)
377{
378 if (reg_classes_intersect_p (class, HILO_REGS)
379 && true_regnum (x) == -1)
380 return GENERAL_REGS;
381
382 return NO_REGS;
383}
384
385/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
386
387int
388crx_hard_regno_mode_ok (int regno, enum machine_mode mode)
389{
390 /* CC can only hold CCmode values. */
391 if (regno == CC_REGNUM)
392 return GET_MODE_CLASS (mode) == MODE_CC;
393 if (GET_MODE_CLASS (mode) == MODE_CC)
394 return 0;
395 /* HILO registers can only hold SImode and DImode */
396 if (HILO_REGNO_P (regno))
397 return mode == SImode || mode == DImode;
398 return 1;
399}
400
401/* PASSING FUNCTION ARGUMENTS */
402/* -------------------------- */
403
404/* If enough param regs are available for passing the param of type TYPE return
405 * the number of registers needed else 0. */
406
407static int
408enough_regs_for_param (CUMULATIVE_ARGS * cum, tree type,
409 enum machine_mode mode)
410{
411 int type_size;
412 int remaining_size;
413
414 if (mode != BLKmode)
415 type_size = GET_MODE_BITSIZE (mode);
416 else
417 type_size = int_size_in_bytes (type) * BITS_PER_UNIT;
418
419 remaining_size =
420 BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS -
421 (MIN_REG_FOR_PASSING_ARGS + cum->ints) + 1);
422
423 /* Any variable which is too big to pass in two registers, will pass on
424 * stack. */
425 if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD))
426 return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD;
427
428 return 0;
429}
430
431/* Implements the macro FUNCTION_ARG defined in crx.h. */
432
433rtx
434crx_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type,
435 int named ATTRIBUTE_UNUSED)
436{
437 last_parm_in_reg = 0;
438
e95cfa3b 439 /* Function_arg () is called with this type just after all the args have had
db869733
PW
440 * their registers assigned. The rtx that function_arg returns from this type
441 * is supposed to pass to 'gen_call' but currently it is not implemented (see
442 * macro GEN_CALL). */
443 if (type == void_type_node)
444 return NULL_RTX;
445
446 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
447 return NULL_RTX;
448
449 if (mode == BLKmode)
450 {
451 /* Enable structures that need padding bytes at the end to pass to a
452 * function in registers. */
453 if (enough_regs_for_param (cum, type, mode) != 0)
454 {
455 last_parm_in_reg = 1;
456 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
457 }
458 }
459
460 if (MIN_REG_FOR_PASSING_ARGS + cum->ints > MAX_REG_FOR_PASSING_ARGS)
461 return NULL_RTX;
462 else
463 {
464 if (enough_regs_for_param (cum, type, mode) != 0)
465 {
466 last_parm_in_reg = 1;
467 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
468 }
469 }
470
471 return NULL_RTX;
472}
473
474/* Implements the macro INIT_CUMULATIVE_ARGS defined in crx.h. */
475
476void
477crx_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
478 rtx libfunc ATTRIBUTE_UNUSED)
479{
480 tree param, next_param;
481
482 cum->ints = 0;
483
484 /* Determine if this function has variable arguments. This is indicated by
485 * the last argument being 'void_type_mode' if there are no variable
486 * arguments. Change here for a different vararg. */
487 for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
488 param != (tree) 0; param = next_param)
489 {
490 next_param = TREE_CHAIN (param);
491 if (next_param == (tree) 0 && TREE_VALUE (param) != void_type_node)
492 {
493 cum->ints = -1;
494 return;
495 }
496 }
497}
498
499/* Implements the macro FUNCTION_ARG_ADVANCE defined in crx.h. */
500
501void
502crx_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
503 tree type, int named ATTRIBUTE_UNUSED)
504{
505 /* l holds the number of registers required */
506 int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
507
508 /* If the parameter isn't passed on a register don't advance cum. */
509 if (!last_parm_in_reg)
510 return;
511
512 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
513 return;
514
515 if (mode == SImode || mode == HImode || mode == QImode || mode == DImode)
516 {
517 if (l <= 1)
518 cum->ints += 1;
519 else
520 cum->ints += l;
521 }
522 else if (mode == SFmode || mode == DFmode)
523 cum->ints += l;
524 else if ((mode) == BLKmode)
525 {
526 if ((l = enough_regs_for_param (cum, type, mode)) != 0)
527 cum->ints += l;
528 }
529
530}
531
a4d05547 532/* Implements the macro FUNCTION_ARG_REGNO_P defined in crx.h. Return nonzero
db869733
PW
533 * if N is a register used for passing parameters. */
534
535int
536crx_function_arg_regno_p (int n)
537{
538 return (n <= MAX_REG_FOR_PASSING_ARGS && n >= MIN_REG_FOR_PASSING_ARGS);
539}
540
541/* ADDRESSING MODES */
542/* ---------------- */
543
544/* Implements the macro GO_IF_LEGITIMATE_ADDRESS defined in crx.h.
e95cfa3b 545 * The following addressing modes are supported on CRX:
db869733
PW
546 *
547 * Relocations --> const | symbol_ref | label_ref
a7b376ee
KH
548 * Absolute address --> 32-bit absolute
549 * Post increment --> reg + 12-bit disp.
550 * Post modify --> reg + 12-bit disp.
551 * Register relative --> reg | 32-bit disp. + reg | 4 bit + reg
552 * Scaled index --> reg + reg | 22-bit disp. + reg + reg |
553 * 22-disp. + reg + reg + (2 | 4 | 8) */
db869733 554
e95cfa3b 555static int crx_addr_reg_p (rtx addr_reg)
db869733 556{
e95cfa3b
PW
557 rtx reg;
558
559 if (REG_P (addr_reg))
db869733 560 {
e95cfa3b
PW
561 reg = addr_reg;
562 }
563 else if ((GET_CODE (addr_reg) == SUBREG
564 && REG_P (SUBREG_REG (addr_reg))
565 && GET_MODE_SIZE (GET_MODE (SUBREG_REG (addr_reg)))
566 <= UNITS_PER_WORD))
567 {
568 reg = SUBREG_REG (addr_reg);
569 }
570 else
571 return FALSE;
db869733 572
e95cfa3b
PW
573 if (GET_MODE (addr_reg) != Pmode)
574 {
575 return FALSE;
db869733
PW
576 }
577
e95cfa3b
PW
578 return TRUE;
579}
580
581enum crx_addrtype
582crx_decompose_address (rtx addr, struct crx_address *out)
583{
584 rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
585 rtx scale_rtx = NULL_RTX, side_effect = NULL_RTX;
586 int scale = -1;
587
588 enum crx_addrtype retval = CRX_INVALID;
589
590 switch (GET_CODE (addr))
db869733 591 {
e95cfa3b
PW
592 case CONST_INT:
593 /* Absolute address (known at compile time) */
594 retval = CRX_ABSOLUTE;
595 disp = addr;
596 if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), GET_MODE_BITSIZE (Pmode)))
597 return CRX_INVALID;
598 break;
599
600 case CONST:
601 case SYMBOL_REF:
602 case LABEL_REF:
603 /* Absolute address (known at link time) */
604 retval = CRX_ABSOLUTE;
605 disp = addr;
606 break;
db869733 607
e95cfa3b
PW
608 case REG:
609 case SUBREG:
610 /* Register relative address */
611 retval = CRX_REG_REL;
612 base = addr;
613 break;
db869733 614
e95cfa3b
PW
615 case PLUS:
616 switch (GET_CODE (XEXP (addr, 0)))
617 {
618 case REG:
619 case SUBREG:
620 if (REG_P (XEXP (addr, 1)))
621 {
622 /* Scaled index with scale = 1 and disp. = 0 */
623 retval = CRX_SCALED_INDX;
624 base = XEXP (addr, 1);
625 index = XEXP (addr, 0);
626 scale = 1;
627 }
628 else if (RTX_SIGNED_INT_FITS_N_BITS (XEXP (addr, 1), 28))
629 {
630 /* Register relative address and <= 28-bit disp. */
631 retval = CRX_REG_REL;
632 base = XEXP (addr, 0);
633 disp = XEXP (addr, 1);
634 }
635 else
636 return CRX_INVALID;
637 break;
db869733 638
e95cfa3b
PW
639 case PLUS:
640 /* Scaled index and <= 22-bit disp. */
641 retval = CRX_SCALED_INDX;
642 base = XEXP (XEXP (addr, 0), 1);
643 disp = XEXP (addr, 1);
644 if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 22))
645 return CRX_INVALID;
646 switch (GET_CODE (XEXP (XEXP (addr, 0), 0)))
647 {
648 case REG:
649 /* Scaled index with scale = 0 and <= 22-bit disp. */
650 index = XEXP (XEXP (addr, 0), 0);
651 scale = 1;
652 break;
653
654 case MULT:
655 /* Scaled index with scale >= 0 and <= 22-bit disp. */
656 index = XEXP (XEXP (XEXP (addr, 0), 0), 0);
657 scale_rtx = XEXP (XEXP (XEXP (addr, 0), 0), 1);
658 if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1)
659 return CRX_INVALID;
660 break;
db869733 661
e95cfa3b
PW
662 default:
663 return CRX_INVALID;
664 }
665 break;
666
667 case MULT:
668 /* Scaled index with scale >= 0 */
669 retval = CRX_SCALED_INDX;
670 base = XEXP (addr, 1);
671 index = XEXP (XEXP (addr, 0), 0);
672 scale_rtx = XEXP (XEXP (addr, 0), 1);
673 /* Scaled index with scale >= 0 and <= 22-bit disp. */
674 if ((scale = SCALE_FOR_INDEX_P (scale_rtx)) == -1)
675 return CRX_INVALID;
676 break;
677
678 default:
679 return CRX_INVALID;
680 }
681 break;
682
683 case POST_INC:
684 case POST_DEC:
685 /* Simple post-increment */
686 retval = CRX_POST_INC;
687 base = XEXP (addr, 0);
688 side_effect = addr;
689 break;
690
691 case POST_MODIFY:
692 /* Generic post-increment with <= 12-bit disp. */
693 retval = CRX_POST_INC;
694 base = XEXP (addr, 0);
695 side_effect = XEXP (addr, 1);
696 if (base != XEXP (side_effect, 0))
697 return CRX_INVALID;
698 switch (GET_CODE (side_effect))
699 {
700 case PLUS:
701 case MINUS:
702 disp = XEXP (side_effect, 1);
703 if (!RTX_SIGNED_INT_FITS_N_BITS (disp, 12))
704 return CRX_INVALID;
705 break;
706
707 default:
708 /* CRX only supports PLUS and MINUS */
709 return CRX_INVALID;
710 }
711 break;
712
713 default:
714 return CRX_INVALID;
db869733
PW
715 }
716
e95cfa3b
PW
717 if (base && !crx_addr_reg_p (base)) return CRX_INVALID;
718 if (index && !crx_addr_reg_p (index)) return CRX_INVALID;
719
720 out->base = base;
721 out->index = index;
722 out->disp = disp;
723 out->scale = scale;
724 out->side_effect = side_effect;
725
726 return retval;
727}
728
729int
730crx_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
731 rtx addr, int strict)
732{
733 enum crx_addrtype addrtype;
734 struct crx_address address;
735
736 if (TARGET_DEBUG_ADDR)
737 {
738 fprintf (stderr,
739 "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
740 GET_MODE_NAME (mode), strict);
741 debug_rtx (addr);
742 }
743
744 addrtype = crx_decompose_address (addr, &address);
745
746 if (addrtype == CRX_POST_INC && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
747 return FALSE;
748
749 if (TARGET_DEBUG_ADDR)
db869733 750 {
e95cfa3b
PW
751 const char *typestr;
752 switch (addrtype)
db869733 753 {
e95cfa3b
PW
754 case CRX_INVALID:
755 typestr = "Invalid";
756 break;
757 case CRX_REG_REL:
758 typestr = "Register relative";
759 break;
760 case CRX_POST_INC:
761 typestr = "Post-increment";
762 break;
763 case CRX_SCALED_INDX:
764 typestr = "Scaled index";
765 break;
766 case CRX_ABSOLUTE:
767 typestr = "Absolute";
768 break;
769 default:
770 abort ();
db869733 771 }
e95cfa3b 772 fprintf (stderr, "CRX Address type: %s\n", typestr);
db869733 773 }
e95cfa3b
PW
774
775 if (addrtype == CRX_INVALID)
776 return FALSE;
db869733 777
e95cfa3b
PW
778 if (strict)
779 {
780 if (address.base && !REGNO_OK_FOR_BASE_P (REGNO (address.base)))
781 {
782 if (TARGET_DEBUG_ADDR)
783 fprintf (stderr, "Base register not strict\n");
784 return FALSE;
785 }
786 if (address.index && !REGNO_OK_FOR_INDEX_P (REGNO (address.index)))
787 {
788 if (TARGET_DEBUG_ADDR)
789 fprintf (stderr, "Index register not strict\n");
790 return FALSE;
791 }
792 }
793
794 return TRUE;
db869733
PW
795}
796
797/* ROUTINES TO COMPUTE COSTS */
798/* ------------------------- */
799
e95cfa3b
PW
800/* Return cost of the memory address x. */
801
802static int
803crx_address_cost (rtx addr)
804{
805 enum crx_addrtype addrtype;
806 struct crx_address address;
807
808 int cost = 2;
809
810 addrtype = crx_decompose_address (addr, &address);
811
812 gcc_assert (addrtype != CRX_INVALID);
813
814 /* An absolute address causes a 3-word instruction */
815 if (addrtype == CRX_ABSOLUTE)
816 cost+=2;
817
57b51d4d 818 /* Post-modifying addresses are more powerful. */
e95cfa3b
PW
819 if (addrtype == CRX_POST_INC)
820 cost-=2;
821
822 /* Attempt to minimize number of registers in the address. */
823 if (address.base)
824 cost++;
825
826 if (address.index && address.scale == 1)
827 cost+=5;
828
55d61dba
PW
829 if (address.disp && !INT_CST4 (INTVAL (address.disp)))
830 cost+=2;
831
832 if (TARGET_DEBUG_ADDR)
833 {
834 fprintf (stderr, "\n======\nTARGET_ADDRESS_COST = %d\n", cost);
835 debug_rtx (addr);
836 }
837
e95cfa3b
PW
838 return cost;
839}
840
db869733
PW
841/* Return the cost of moving data of mode MODE between a register of class
842 * CLASS and memory; IN is zero if the value is to be written to memory,
a4d05547
KH
843 * nonzero if it is to be read in. This cost is relative to those in
844 * REGISTER_MOVE_COST. */
db869733
PW
845
846int
847crx_memory_move_cost (enum machine_mode mode,
848 enum reg_class class ATTRIBUTE_UNUSED,
849 int in ATTRIBUTE_UNUSED)
850{
851 /* One LD or ST takes twice the time of a simple reg-reg move */
852 if (reg_classes_intersect_p (class, GENERAL_REGS))
853 {
e95cfa3b 854 /* printf ("GENERAL_REGS LD/ST = %d\n", 4 * HARD_REGNO_NREGS (0, mode));*/
db869733
PW
855 return 4 * HARD_REGNO_NREGS (0, mode);
856 }
857 else if (reg_classes_intersect_p (class, HILO_REGS))
858 {
859 /* HILO to memory and vice versa */
e95cfa3b
PW
860 /* printf ("HILO_REGS %s = %d\n", in ? "LD" : "ST",
861 (REGISTER_MOVE_COST (mode,
db869733
PW
862 in ? GENERAL_REGS : HILO_REGS,
863 in ? HILO_REGS : GENERAL_REGS) + 4)
864 * HARD_REGNO_NREGS (0, mode)); */
e95cfa3b 865 return (REGISTER_MOVE_COST (mode,
db869733
PW
866 in ? GENERAL_REGS : HILO_REGS,
867 in ? HILO_REGS : GENERAL_REGS) + 4)
868 * HARD_REGNO_NREGS (0, mode);
869 }
870 else /* default (like in i386) */
871 {
e95cfa3b 872 /* printf ("ANYREGS = 100\n"); */
db869733
PW
873 return 100;
874 }
875}
876
877/* INSTRUCTION OUTPUT */
878/* ------------------ */
879
db869733
PW
880/* Check if a const_double is ok for crx store-immediate instructions */
881
882int
883crx_const_double_ok (rtx op)
884{
885 if (GET_MODE (op) == DFmode)
886 {
887 REAL_VALUE_TYPE r;
888 long l[2];
889 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
890 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
e95cfa3b
PW
891 return (UNSIGNED_INT_FITS_N_BITS (l[0], 4) &&
892 UNSIGNED_INT_FITS_N_BITS (l[1], 4)) ? 1 : 0;
db869733
PW
893 }
894
895 if (GET_MODE (op) == SFmode)
896 {
897 REAL_VALUE_TYPE r;
898 long l;
899 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
900 REAL_VALUE_TO_TARGET_SINGLE (r, l);
e95cfa3b 901 return UNSIGNED_INT_FITS_N_BITS (l, 4) ? 1 : 0;
db869733
PW
902 }
903
904 return (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4) &&
905 UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4)) ? 1 : 0;
906}
907
908/* Implements the macro PRINT_OPERAND defined in crx.h. */
909
910void
911crx_print_operand (FILE * file, rtx x, int code)
912{
913 switch (code)
914 {
915 case 'p' :
916 if (GET_CODE (x) == REG) {
917 if (GET_MODE (x) == DImode || GET_MODE (x) == DFmode)
918 {
919 int regno = REGNO (x);
920 if (regno + 1 >= SP_REGNUM) abort ();
921 fprintf (file, "{%s, %s}", reg_names[regno], reg_names[regno + 1]);
922 return;
923 }
924 else
925 {
926 if (REGNO (x) >= SP_REGNUM) abort ();
927 fprintf (file, "%s", reg_names[REGNO (x)]);
928 return;
929 }
930 }
931
932 case 'd' :
933 {
934 const char *crx_cmp_str;
935 switch (GET_CODE (x))
e95cfa3b 936 { /* MD: compare (reg, reg or imm) but CRX: cmp (reg or imm, reg)
db869733
PW
937 * -> swap all non symmetric ops */
938 case EQ : crx_cmp_str = "eq"; break;
939 case NE : crx_cmp_str = "ne"; break;
940 case GT : crx_cmp_str = "lt"; break;
941 case GTU : crx_cmp_str = "lo"; break;
942 case LT : crx_cmp_str = "gt"; break;
943 case LTU : crx_cmp_str = "hi"; break;
944 case GE : crx_cmp_str = "le"; break;
945 case GEU : crx_cmp_str = "ls"; break;
946 case LE : crx_cmp_str = "ge"; break;
947 case LEU : crx_cmp_str = "hs"; break;
948 default : abort ();
949 }
950 fprintf (file, "%s", crx_cmp_str);
951 return;
952 }
953
954 case 'H':
955 /* Print high part of a double precision value. */
956 switch (GET_CODE (x))
957 {
958 case CONST_DOUBLE:
959 if (GET_MODE (x) == SFmode) abort ();
960 if (GET_MODE (x) == DFmode)
961 {
962 /* High part of a DF const. */
963 REAL_VALUE_TYPE r;
964 long l[2];
965
966 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
967 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
968
969 fprintf (file, "$0x%lx", l[1]);
970 return;
971 }
972
973 /* -- Fallthrough to handle DI consts -- */
974
975 case CONST_INT:
976 {
977 rtx high, low;
978 split_double (x, &low, &high);
979 putc ('$', file);
980 output_addr_const (file, high);
981 return;
982 }
983
984 case REG:
985 if (REGNO (x) + 1 >= FIRST_PSEUDO_REGISTER) abort ();
986 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
987 return;
988
989 case MEM:
990 /* Adjust memory address to high part. */
991 {
992 rtx adj_mem = x;
993 adj_mem = adjust_address (adj_mem, GET_MODE (adj_mem), 4);
994
995 output_memory_reference_mode = GET_MODE (adj_mem);
996 output_address (XEXP (adj_mem, 0));
997 return;
998 }
999
1000 default:
1001 abort ();
1002 }
1003
1004 case 'L':
1005 /* Print low part of a double precision value. */
1006 switch (GET_CODE (x))
1007 {
1008 case CONST_DOUBLE:
1009 if (GET_MODE (x) == SFmode) abort ();
1010 if (GET_MODE (x) == DFmode)
1011 {
1012 /* High part of a DF const. */
1013 REAL_VALUE_TYPE r;
1014 long l[2];
1015
1016 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1017 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1018
1019 fprintf (file, "$0x%lx", l[0]);
1020 return;
1021 }
1022
1023 /* -- Fallthrough to handle DI consts -- */
1024
1025 case CONST_INT:
1026 {
1027 rtx high, low;
1028 split_double (x, &low, &high);
1029 putc ('$', file);
1030 output_addr_const (file, low);
1031 return;
1032 }
1033
1034 case REG:
1035 fprintf (file, "%s", reg_names[REGNO (x)]);
1036 return;
1037
1038 case MEM:
1039 output_memory_reference_mode = GET_MODE (x);
1040 output_address (XEXP (x, 0));
1041 return;
1042
1043 default:
1044 abort ();
1045 }
1046
1047 case 0 : /* default */
e95cfa3b 1048 switch (GET_CODE (x))
db869733
PW
1049 {
1050 case REG:
1051 fprintf (file, "%s", reg_names[REGNO (x)]);
1052 return;
1053
1054 case MEM:
1055 output_memory_reference_mode = GET_MODE (x);
1056 output_address (XEXP (x, 0));
1057 return;
1058
1059 case CONST_DOUBLE:
1060 {
1061 REAL_VALUE_TYPE r;
1062 long l;
1063
1064 /* Always use H and L for double precision - see above */
e95cfa3b 1065 gcc_assert (GET_MODE (x) == SFmode);
db869733
PW
1066
1067 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1068 REAL_VALUE_TO_TARGET_SINGLE (r, l);
1069
1070 fprintf (file, "$0x%lx", l);
1071 return;
1072 }
1073
1074 default:
1075 putc ('$', file);
1076 output_addr_const (file, x);
1077 return;
1078 }
1079
1080 default:
1081 output_operand_lossage ("invalid %%xn code");
1082 }
1083
1084 abort ();
1085}
1086
1087/* Implements the macro PRINT_OPERAND_ADDRESS defined in crx.h. */
1088
1089void
1090crx_print_operand_address (FILE * file, rtx addr)
1091{
e95cfa3b
PW
1092 enum crx_addrtype addrtype;
1093 struct crx_address address;
1094
1095 int offset;
1096
1097 addrtype = crx_decompose_address (addr, &address);
1098
1099 if (address.disp)
1100 offset = INTVAL (address.disp);
1101 else
1102 offset = 0;
db869733 1103
e95cfa3b 1104 switch (addrtype)
db869733 1105 {
e95cfa3b
PW
1106 case CRX_REG_REL:
1107 fprintf (file, "%d(%s)", offset, reg_names[REGNO (address.base)]);
1108 return;
1109
1110 case CRX_POST_INC:
1111 switch (GET_CODE (address.side_effect))
db869733 1112 {
e95cfa3b 1113 case PLUS:
db869733 1114 break;
e95cfa3b
PW
1115 case MINUS:
1116 offset = -offset;
db869733 1117 break;
e95cfa3b
PW
1118 case POST_INC:
1119 offset = GET_MODE_SIZE (output_memory_reference_mode);
db869733 1120 break;
e95cfa3b
PW
1121 case POST_DEC:
1122 offset = -GET_MODE_SIZE (output_memory_reference_mode);
db869733 1123 break;
e95cfa3b
PW
1124 default:
1125 abort ();
db869733 1126 }
e95cfa3b
PW
1127 fprintf (file, "%d(%s)+", offset, reg_names[REGNO (address.base)]);
1128 return;
1129
1130 case CRX_SCALED_INDX:
1131 fprintf (file, "%d(%s, %s, %d)", offset, reg_names[REGNO (address.base)],
1132 reg_names[REGNO (address.index)], address.scale);
1133 return;
1134
1135 case CRX_ABSOLUTE:
1136 output_addr_const (file, address.disp);
1137 return;
1138
db869733 1139 default:
e95cfa3b 1140 abort ();
db869733 1141 }
db869733
PW
1142}
1143
1144
1145/*****************************************************************************/
1146/* MACHINE DESCRIPTION HELPER-FUNCTIONS */
1147/*****************************************************************************/
1148
1149void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase,
1150 rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p)
1151{
1152 rtx addr, mem;
1153 unsigned HOST_WIDE_INT offset = *offset_p;
1154
1155 /* Load */
1156 addr = plus_constant (src, offset);
1157 mem = adjust_automodify_address (srcbase, SImode, addr, offset);
1158 emit_move_insn (tmp_reg, mem);
1159
1160 /* Store */
1161 addr = plus_constant (dst, offset);
1162 mem = adjust_automodify_address (dstbase, SImode, addr, offset);
1163 emit_move_insn (mem, tmp_reg);
1164
1165 *offset_p = offset + 4;
1166}
1167
1168int
1169crx_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp)
1170{
1171 unsigned HOST_WIDE_INT count = 0, offset, si_moves, i;
1172 HOST_WIDE_INT align = 0;
1173
1174 rtx src, dst;
1175 rtx tmp_reg;
1176
1177 if (GET_CODE (align_exp) == CONST_INT)
1178 { /* Only if aligned */
1179 align = INTVAL (align_exp);
e95cfa3b
PW
1180 if (align & 3)
1181 return 0;
db869733
PW
1182 }
1183
1184 if (GET_CODE (count_exp) == CONST_INT)
1185 { /* No more than 16 SImode moves */
1186 count = INTVAL (count_exp);
e95cfa3b
PW
1187 if (count > 64)
1188 return 0;
db869733
PW
1189 }
1190
e95cfa3b 1191 tmp_reg = gen_reg_rtx (SImode);
db869733
PW
1192
1193 /* Create psrs for the src and dest pointers */
1194 dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0));
1195 if (dst != XEXP (dstbase, 0))
1196 dstbase = replace_equiv_address_nv (dstbase, dst);
1197 src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0));
1198 if (src != XEXP (srcbase, 0))
1199 srcbase = replace_equiv_address_nv (srcbase, src);
1200
1201 offset = 0;
1202
1203 /* Emit SImode moves */
1204 si_moves = count >> 2;
1205 for (i = 0; i < si_moves; i++)
1206 crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
1207
1208 /* Special cases */
1209 if (count & 3)
1210 {
1211 offset = count - 4;
1212 crx_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
1213 }
1214
1215 gcc_assert (offset == count);
1216
1217 return 1;
1218}
1219
1220rtx
1221crx_expand_compare (enum rtx_code code, enum machine_mode mode)
1222{
1223 rtx op0, op1, cc_reg, ret;
1224
1225 op0 = crx_compare_op0;
1226 op1 = crx_compare_op1;
1227
1228 /* Emit the compare that writes into CC_REGNUM) */
1229 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
1230 ret = gen_rtx_COMPARE (CCmode, op0, op1);
1231 emit_insn (gen_rtx_SET (VOIDmode, cc_reg, ret));
1232 /* debug_rtx (get_last_insn ()); */
1233
1234 /* Return the rtx for using the result in CC_REGNUM */
1235 return gen_rtx_fmt_ee (code, mode, cc_reg, const0_rtx);
1236}
1237
1238void
1239crx_expand_branch (enum rtx_code code, rtx label)
1240{
1241 rtx tmp = crx_expand_compare (code, VOIDmode);
1242 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
1243 gen_rtx_LABEL_REF (VOIDmode, label),
1244 pc_rtx);
1245 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
1246 /* debug_rtx (get_last_insn ()); */
1247}
1248
1249void
1250crx_expand_scond (enum rtx_code code, rtx dest)
1251{
1252 rtx tmp = crx_expand_compare (code, GET_MODE (dest));
1253 emit_move_insn (dest, tmp);
1254 /* debug_rtx (get_last_insn ()); */
1255}
1256
1257static void
1258mpushpop_str (char *stringbuffer, const char *mnemonic, char *mask)
1259{
e95cfa3b 1260 if (strlen (mask) > 2 || crx_interrupt_function_p ()) /* needs 2-word instr. */
db869733
PW
1261 sprintf (stringbuffer, "\n\t%s\tsp, {%s}", mnemonic, mask);
1262 else /* single word instruction */
1263 sprintf (stringbuffer, "\n\t%s\t%s", mnemonic, mask);
1264}
1265
1266/* Called from crx.md. The return value depends on the parameter push_or_pop:
1267 * When push_or_pop is zero -> string for push instructions of prologue.
1268 * When push_or_pop is nonzero -> string for pop/popret/retx in epilogue.
1269 * Relies on the assumptions:
1270 * 1. RA is the last register to be saved.
1271 * 2. The maximal value of the counter is MAX_COUNT. */
1272
1273char *
1274crx_prepare_push_pop_string (int push_or_pop)
1275{
1276 /* j is the number of registers being saved, takes care that there won't be
1277 * more than 8 in one push/pop instruction */
1278
1279 /* For the register mask string */
1280 static char mask_str[50];
1281
1282 /* i is the index of save_regs[], going from 0 until last_reg_to_save */
1283 int i = 0;
1284
1285 int ra_in_bitmask = 0;
1286
1287 char *return_str;
1288
1289 /* For reversing on the push instructions if there are more than one. */
1290 char *temp_str;
1291
1292 return_str = (char *) xmalloc (120);
1293 temp_str = (char *) xmalloc (120);
1294
1295 /* Initialize */
1296 memset (return_str, 0, 3);
1297
1298 while (i <= last_reg_to_save)
1299 {
1300 /* Prepare mask for one instruction. */
1301 mask_str[0] = 0;
1302
1303 if (i <= SP_REGNUM)
1304 { /* Add regs unit full or SP register reached */
1305 int j = 0;
1306 while (j < MAX_COUNT && i <= SP_REGNUM)
1307 {
1308 if (save_regs[i])
1309 {
1310 /* TODO to use ra_in_bitmask for detecting last pop is not
1311 * smart it prevents things like: popret r5 */
1312 if (i == RETURN_ADDRESS_REGNUM) ra_in_bitmask = 1;
1313 if (j > 0) strcat (mask_str, ", ");
1314 strcat (mask_str, reg_names[i]);
1315 ++j;
1316 }
1317 ++i;
1318 }
1319 }
1320 else
1321 {
1322 /* Handle hi/lo savings */
1323 while (i <= last_reg_to_save)
1324 {
1325 if (save_regs[i])
1326 {
1327 strcat (mask_str, "lo, hi");
1328 i = last_reg_to_save + 1;
1329 break;
1330 }
1331 ++i;
1332 }
1333 }
1334
e95cfa3b 1335 if (strlen (mask_str) == 0) continue;
db869733
PW
1336
1337 if (push_or_pop == 1)
1338 {
1339 if (crx_interrupt_function_p ())
1340 mpushpop_str (temp_str, "popx", mask_str);
1341 else
1342 {
1343 if (ra_in_bitmask)
1344 {
1345 mpushpop_str (temp_str, "popret", mask_str);
1346 ra_in_bitmask = 0;
1347 }
1348 else mpushpop_str (temp_str, "pop", mask_str);
1349 }
1350
1351 strcat (return_str, temp_str);
1352 }
1353 else
1354 {
1355 /* push - We need to reverse the order of the instructions if there
1356 * are more than one. (since the pop will not be reversed in the
1357 * epilogue */
1358 if (crx_interrupt_function_p ())
1359 mpushpop_str (temp_str, "pushx", mask_str);
1360 else
1361 mpushpop_str (temp_str, "push", mask_str);
1362 strcat (temp_str, return_str);
1363 strcpy (strcat (return_str, "\t"), temp_str);
1364 }
1365
1366 }
1367
1368 if (push_or_pop == 1)
1369 {
1370 /* pop */
1371 if (crx_interrupt_function_p ())
1372 strcat (return_str, "\n\tretx\n");
1373
1374 else if (!FUNC_IS_NORETURN_P (current_function_decl)
1375 && !save_regs[RETURN_ADDRESS_REGNUM])
1376 strcat (return_str, "\n\tjump\tra\n");
1377 }
1378
1379 /* Skip the newline and the tab in the start of return_str. */
1380 return_str += 2;
1381 return return_str;
1382}
1383
1384/* CompactRISC CRX Architecture stack layout:
1385
1386 0 +---------------------
1387 |
1388 .
1389 .
1390 |
1391 +==================== Sp(x)=Ap(x+1)
1392 A | Args for functions
1393 | | called by X and Dynamically
1394 | | Dynamic allocations allocated and
1395 | | (alloca, variable deallocated
1396 Stack | length arrays).
1397 grows +-------------------- Fp(x)
a4174ebf 1398 down| | Local variables of X
db869733
PW
1399 ward| +--------------------
1400 | | Regs saved for X-1
1401 | +==================== Sp(x-1)=Ap(x)
1402 | Args for func X
1403 | pushed by X-1
1404 +-------------------- Fp(x-1)
1405 |
1406 |
1407 V
1408
1409*/
1410
1411void
1412crx_expand_prologue (void)
1413{
1414 crx_compute_frame ();
1415 crx_compute_save_regs ();
1416
1417 /* If there is no need in push and adjustment to sp, return. */
1418 if (size_for_adjusting_sp + sum_regs == 0)
1419 return;
1420
1421 if (last_reg_to_save != -1)
1422 /* If there are registers to push. */
1423 emit_insn (gen_push_for_prologue (GEN_INT (sum_regs)));
1424
1425 if (size_for_adjusting_sp > 0)
1426 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
e95cfa3b 1427 GEN_INT (-size_for_adjusting_sp)));
db869733
PW
1428
1429 if (frame_pointer_needed)
1430 /* Initialize the frame pointer with the value of the stack pointer
1431 * pointing now to the locals. */
1432 emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
1433}
1434
1435/* Generate insn that updates the stack for local variables and padding for
1436 * registers we save. - Generate the appropriate return insn. */
1437
1438void
1439crx_expand_epilogue (void)
1440{
1441 rtx return_reg;
1442
1443 /* Nonzero if we need to return and pop only RA. This will generate a
1444 * different insn. This differentiate is for the peepholes for call as last
1445 * statement in function. */
1446 int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM]
1447 && (sum_regs == UNITS_PER_WORD));
1448
1449 /* Return register. */
1450 return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);
1451
1452 if (frame_pointer_needed)
1453 /* Restore the stack pointer with the frame pointers value */
1454 emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
1455
1456 if (size_for_adjusting_sp > 0)
1457 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1458 GEN_INT (size_for_adjusting_sp)));
1459
1460 if (crx_interrupt_function_p ())
1461 emit_jump_insn (gen_interrupt_return ());
1462 else if (last_reg_to_save == -1)
1463 /* Nothing to pop */
1464 /* Don't output jump for interrupt routine, only retx. */
1465 emit_jump_insn (gen_indirect_jump_return ());
1466 else if (only_popret_RA)
1467 emit_jump_insn (gen_popret_RA_return ());
1468 else
1469 emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs)));
1470}
1471