1 /* Subroutines for insn-output.c for Clipper
2 Copyright (C) 1987, 1988, 1991, 1997, 1998,
3 1999, 2000 Free Software Foundation, Inc.
4 Contributed by Holger Teutsch (holger@hotbso.rhein-main.de)
6 This file is part of GNU CC.
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-flags.h"
33 #include "insn-attr.h"
42 extern char regs_ever_live
[];
44 extern int frame_pointer_needed
;
46 static int frame_size
;
48 /* Compute size of a clipper stack frame where 'lsize' is the required
49 space for local variables. */
52 clipper_frame_size (lsize
)
55 int i
, size
; /* total size of frame */
57 save_size
= 0; /* compute size for reg saves */
59 for (i
= 16; i
< 32; i
++)
60 if (regs_ever_live
[i
] && !call_used_regs
[i
])
63 for (i
= 0; i
< 16; i
++)
64 if (regs_ever_live
[i
] && !call_used_regs
[i
])
67 size
= lsize
+ save_size
;
69 size
= (size
+ 7) & ~7; /* align to 64 Bit */
73 /* Prologue and epilogue output
74 Function is entered with pc pushed, i.e. stack is 32 bit aligned
76 current_function_args_size == 0 means that the current function's args
77 are passed totally in registers i.e fp is not used as ap.
78 If frame_size is also 0 the current function does not push anything and
79 can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
83 output_function_prologue (file
, lsize
)
85 int lsize
; /* size for locals */
90 frame_size
= size
= clipper_frame_size (lsize
);
92 if (frame_pointer_needed
)
94 fputs ("\tpushw fp,sp\n", file
);
95 fputs ("\tmovw sp,fp\n", file
);
97 else if (size
!= 0 || current_function_args_size
!= 0)
99 size
+= 4; /* keep stack aligned */
100 frame_size
= size
; /* must push data or access args */
106 fprintf (file
, "\tsubq $%d,sp\n", size
);
108 fprintf (file
, "\tsubi $%d,sp\n", size
);
110 /* register save slots are relative to sp, because we have small positive
111 displacements and this works whether we have a frame pointer or not */
114 for (i
= 16; i
< 32; i
++)
115 if (regs_ever_live
[i
] && !call_used_regs
[i
])
118 fprintf (file
, "\tstord f%d,(sp)\n", i
-16);
120 fprintf (file
, "\tstord f%d,%d(sp)\n", i
-16, offset
);
124 for (i
= 0; i
< 16; i
++)
125 if (regs_ever_live
[i
] && !call_used_regs
[i
])
128 fprintf (file
, "\tstorw r%d,(sp)\n", i
);
130 fprintf (file
, "\tstorw r%d,%d(sp)\n", i
, offset
);
137 output_function_epilogue (file
, size
)
139 int size ATTRIBUTE_UNUSED
;
143 if (frame_pointer_needed
)
145 offset
= -frame_size
;
147 for (i
= 16; i
< 32; i
++)
148 if (regs_ever_live
[i
] && !call_used_regs
[i
])
150 fprintf (file
, "\tloadd %d(fp),f%d\n", offset
, i
-16);
154 for (i
= 0; i
< 16; i
++)
155 if (regs_ever_live
[i
] && !call_used_regs
[i
])
157 fprintf (file
, "\tloadw %d(fp),r%d\n", offset
, i
);
161 fputs ("\tmovw fp,sp\n\tpopw sp,fp\n\tret sp\n",
165 else /* no frame pointer */
169 for (i
= 16; i
< 32; i
++)
170 if (regs_ever_live
[i
] && !call_used_regs
[i
])
173 fprintf (file
, "\tloadd (sp),f%d\n", i
-16);
175 fprintf (file
, "\tloadd %d(sp),f%d\n", offset
, i
-16);
179 for (i
= 0; i
< 16; i
++)
180 if (regs_ever_live
[i
] && !call_used_regs
[i
])
183 fprintf (file
, "\tloadw (sp),r%d\n", i
);
185 fprintf (file
, "\tloadw %d(sp),r%d\n", offset
, i
);
192 fprintf (file
, "\taddq $%d,sp\n", frame_size
);
194 fprintf (file
, "\taddi $%d,sp\n", frame_size
);
197 fputs ("\tret sp\n", file
);
207 clipper_movstr (operands
)
210 rtx dst
,src
,cnt
,tmp
,top
,bottom
,xops
[3];
214 extern FILE *asm_out_file
;
218 /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
219 align
= INTVAL (operands
[3]);
223 if (GET_CODE (operands
[2]) == CONST_INT
) /* fixed size move */
225 if ((fixed
= INTVAL (operands
[2])) <= 0)
229 output_asm_insn ("loadq %2,%5", operands
);
231 output_asm_insn ("loadi %2,%5", operands
);
236 bottom
= (rtx
)gen_label_rtx (); /* need a bottom label */
237 xops
[0] = cnt
; xops
[1] = bottom
;
238 output_asm_insn ("movw %2,%5", operands
); /* count is scratch reg 5 */
239 output_asm_insn ("brle %l1", xops
);
243 top
= (rtx
)gen_label_rtx (); /* top of loop label */
244 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, "L", CODE_LABEL_NUMBER (top
));
247 xops
[0] = src
; xops
[1] = tmp
; xops
[2] = dst
;
249 if (fixed
&& (align
& 0x3) == 0) /* word aligned move with known size */
255 "loadw %a0,%1\n\taddq $4,%0\n\tstorw %1,%a2\n\taddq $4,%2",
258 xops1
[0] = cnt
; xops1
[1] = top
;
259 output_asm_insn ("subq $4,%0\n\tbrgt %l1", xops1
);
264 output_asm_insn ("loadh %a0,%1\n\tstorh %1,%a2", xops
);
266 output_asm_insn ("loadb 2%a0,%1\n\tstorb %1,2%a2", xops
);
270 output_asm_insn ("loadb %a0,%1\n\tstorb %1,%a2", xops
);
275 "loadb %a0,%1\n\taddq $1,%0\n\tstorb %1,%a2\n\taddq $1,%2",
278 xops
[0] = cnt
; xops
[1] = top
;
279 output_asm_insn ("subq $1,%0\n\tbrgt %l1", xops
);
283 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, "L", CODE_LABEL_NUMBER (bottom
));
288 print_operand_address (file
, addr
)
294 switch (GET_CODE (addr
))
297 fprintf (file
, "(%s)", reg_names
[REGNO (addr
)]);
301 /* can be 'symbol + reg' or 'reg + reg' */
303 op0
= XEXP (addr
, 0);
304 op1
= XEXP (addr
, 1);
306 if (GET_CODE (op0
) == REG
&& GET_CODE (op1
) == REG
)
308 fprintf (file
, "[%s](%s)",
309 reg_names
[REGNO (op0
)], reg_names
[REGNO (op1
)]);
313 if (GET_CODE (op0
) == REG
&& CONSTANT_ADDRESS_P (op1
))
315 output_addr_const (file
, op1
);
316 fprintf (file
, "(%s)", reg_names
[REGNO (op0
)]);
320 if (GET_CODE (op1
) == REG
&& CONSTANT_ADDRESS_P (op0
))
322 output_addr_const (file
, op0
);
323 fprintf (file
, "(%s)", reg_names
[REGNO (op1
)]);
326 abort (); /* Oh no */
329 output_addr_const (file
, addr
);
338 switch (GET_CODE (op
))
367 /* Dump the argument register to the stack; return the location
371 clipper_builtin_saveregs ()
373 rtx block
, addr
, r0_addr
, r1_addr
, f0_addr
, f1_addr
, mem
;
374 int set
= get_varargs_alias_set ();
376 /* Allocate the save area for r0,r1,f0,f1 */
378 block
= assign_stack_local (BLKmode
, 6 * UNITS_PER_WORD
, 2 * BITS_PER_WORD
);
380 RTX_UNCHANGING_P (block
) = 1;
381 RTX_UNCHANGING_P (XEXP (block
, 0)) = 1;
383 addr
= XEXP (block
, 0);
386 r1_addr
= plus_constant (addr
, 4);
387 f0_addr
= plus_constant (addr
, 8);
388 f1_addr
= plus_constant (addr
, 16);
392 mem
= gen_rtx_MEM (SImode
, r0_addr
);
393 MEM_ALIAS_SET (mem
) = set
;
394 emit_move_insn (mem
, gen_rtx_REG (SImode
, 0));
396 mem
= gen_rtx_MEM (SImode
, r1_addr
);
397 MEM_ALIAS_SET (mem
) = set
;
398 emit_move_insn (mem
, gen_rtx_REG (SImode
, 1));
400 /* Store float regs */
402 mem
= gen_rtx_MEM (DFmode
, f0_addr
);
403 MEM_ALIAS_SET (mem
) = set
;
404 emit_move_insn (mem
, gen_rtx_REG (DFmode
, 16));
406 mem
= gen_rtx_MEM (DFmode
, f1_addr
);
407 MEM_ALIAS_SET (mem
) = set
;
408 emit_move_insn (mem
, gen_rtx_REG (DFmode
, 17));
410 if (current_function_check_memory_usage
)
412 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
414 GEN_INT (GET_MODE_SIZE (DFmode
)),
415 TYPE_MODE (sizetype
),
416 GEN_INT (MEMORY_USE_RW
),
417 TYPE_MODE (integer_type_node
));
418 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
420 GEN_INT (GET_MODE_SIZE (DFmode
)),
421 TYPE_MODE (sizetype
),
422 GEN_INT (MEMORY_USE_RW
),
423 TYPE_MODE (integer_type_node
));
424 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
426 GEN_INT (GET_MODE_SIZE (SImode
)),
427 TYPE_MODE (sizetype
),
428 GEN_INT (MEMORY_USE_RW
),
429 TYPE_MODE (integer_type_node
));
430 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
432 GEN_INT (GET_MODE_SIZE (SImode
)),
433 TYPE_MODE (sizetype
),
434 GEN_INT (MEMORY_USE_RW
),
435 TYPE_MODE (integer_type_node
));
442 clipper_build_va_list ()
444 tree record
, ap
, reg
, num
;
449 int __va_ap; // pointer to stack args
450 void *__va_reg[4]; // pointer to r0,f0,r1,f1
451 int __va_num; // number of args processed
455 record
= make_node (RECORD_TYPE
);
457 num
= build_decl (FIELD_DECL
, get_identifier ("__va_num"),
459 DECL_FIELD_CONTEXT (num
) = record
;
461 reg
= build_decl (FIELD_DECL
, get_identifier ("__va_reg"),
462 build_array_type (ptr_type_node
,
463 build_index_type (build_int_2 (3, 0))));
464 DECL_FIELD_CONTEXT (reg
) = record
;
465 TREE_CHAIN (reg
) = num
;
467 ap
= build_decl (FIELD_DECL
, get_identifier ("__va_ap"),
469 DECL_FIELD_CONTEXT (ap
) = record
;
470 TREE_CHAIN (ap
) = reg
;
472 TYPE_FIELDS (record
) = ap
;
473 layout_type (record
);
479 clipper_va_start (stdarg_p
, valist
, nextarg
)
482 rtx nextarg ATTRIBUTE_UNUSED
;
484 tree ap_field
, reg_field
, num_field
;
485 tree t
, u
, save_area
;
487 ap_field
= TYPE_FIELDS (TREE_TYPE (valist
));
488 reg_field
= TREE_CHAIN (ap_field
);
489 num_field
= TREE_CHAIN (reg_field
);
491 ap_field
= build (COMPONENT_REF
, TREE_TYPE (ap_field
), valist
, ap_field
);
492 reg_field
= build (COMPONENT_REF
, TREE_TYPE (reg_field
), valist
, reg_field
);
493 num_field
= build (COMPONENT_REF
, TREE_TYPE (num_field
), valist
, num_field
);
495 /* Call __builtin_saveregs to save r0, r1, f0, and f1 in a block. */
497 save_area
= make_tree (integer_type_node
, expand_builtin_saveregs ());
501 t
= make_tree (ptr_type_node
, virtual_incoming_args_rtx
);
502 if (stdarg_p
&& current_function_args_info
.size
!= 0)
503 t
= build (PLUS_EXPR
, ptr_type_node
, t
,
504 build_int_2 (current_function_args_info
.size
, 0));
505 t
= build (MODIFY_EXPR
, TREE_TYPE (ap_field
), ap_field
, t
);
506 TREE_SIDE_EFFECTS (t
) = 1;
507 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
509 /* Set the four entries of __va_reg. */
511 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
512 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (0, 0));
513 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
514 TREE_SIDE_EFFECTS (t
) = 1;
515 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
517 t
= fold (build (PLUS_EXPR
, integer_type_node
, save_area
,
518 build_int_2 (8, 0)));
519 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
520 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (1, 0));
521 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
522 TREE_SIDE_EFFECTS (t
) = 1;
523 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
525 t
= fold (build (PLUS_EXPR
, integer_type_node
, save_area
,
526 build_int_2 (4, 0)));
527 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
528 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (2, 0));
529 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
530 TREE_SIDE_EFFECTS (t
) = 1;
531 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
533 t
= fold (build (PLUS_EXPR
, integer_type_node
, save_area
,
534 build_int_2 (16, 0)));
535 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
536 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (3, 0));
537 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
538 TREE_SIDE_EFFECTS (t
) = 1;
539 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
543 t
= build_int_2 (current_function_args_info
.num
, 0);
544 t
= build (MODIFY_EXPR
, TREE_TYPE (num_field
), num_field
, t
);
545 TREE_SIDE_EFFECTS (t
) = 1;
546 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
550 clipper_va_arg (valist
, type
)
553 tree ap_field
, reg_field
, num_field
;
556 rtx addr_rtx
, over_label
= NULL_RTX
, tr
;
562 addr = VA.__va_reg[2 * VA.__va_num];
564 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
570 addr = VA.__va_reg[2 * VA.__va_num + 1];
572 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
577 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
581 ap_field
= TYPE_FIELDS (TREE_TYPE (valist
));
582 reg_field
= TREE_CHAIN (ap_field
);
583 num_field
= TREE_CHAIN (reg_field
);
585 ap_field
= build (COMPONENT_REF
, TREE_TYPE (ap_field
), valist
, ap_field
);
586 reg_field
= build (COMPONENT_REF
, TREE_TYPE (reg_field
), valist
, reg_field
);
587 num_field
= build (COMPONENT_REF
, TREE_TYPE (num_field
), valist
, num_field
);
589 addr_rtx
= gen_reg_rtx (Pmode
);
591 if (! AGGREGATE_TYPE_P (type
))
596 over_label
= gen_label_rtx ();
597 false_label
= gen_label_rtx ();
599 emit_cmp_and_jump_insns (expand_expr (num_field
, NULL_RTX
, 0,
601 GEN_INT (2), GE
, const0_rtx
,
602 TYPE_MODE (TREE_TYPE (num_field
)),
603 TREE_UNSIGNED (num_field
), 0, false_label
);
605 inreg
= fold (build (MULT_EXPR
, integer_type_node
, num_field
,
606 build_int_2 (2, 0)));
607 if (FLOAT_TYPE_P (type
))
608 inreg
= fold (build (PLUS_EXPR
, integer_type_node
, inreg
,
609 build_int_2 (1, 0)));
610 inreg
= fold (build (ARRAY_REF
, ptr_type_node
, reg_field
, inreg
));
612 tr
= expand_expr (inreg
, addr_rtx
, VOIDmode
, EXPAND_NORMAL
);
614 emit_move_insn (addr_rtx
, tr
);
616 emit_jump_insn (gen_jump (over_label
));
618 emit_label (false_label
);
621 /* Round to alignment of `type', or at least integer alignment. */
623 align
= TYPE_ALIGN (type
);
624 if (align
< TYPE_ALIGN (integer_type_node
))
625 align
= TYPE_ALIGN (integer_type_node
);
626 align
/= BITS_PER_UNIT
;
628 addr
= fold (build (PLUS_EXPR
, ptr_type_node
, ap_field
,
629 build_int_2 (align
-1, 0)));
630 addr
= fold (build (BIT_AND_EXPR
, ptr_type_node
, addr
,
631 build_int_2 (-align
, -1)));
632 addr
= save_expr (addr
);
634 tr
= expand_expr (addr
, addr_rtx
, Pmode
, EXPAND_NORMAL
);
636 emit_move_insn (addr_rtx
, tr
);
638 t
= build (MODIFY_EXPR
, TREE_TYPE (ap_field
), ap_field
,
639 build (PLUS_EXPR
, TREE_TYPE (ap_field
),
640 addr
, build_int_2 (int_size_in_bytes (type
), 0)));
641 TREE_SIDE_EFFECTS (t
) = 1;
642 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
645 emit_label (over_label
);
647 t
= build (MODIFY_EXPR
, TREE_TYPE (num_field
), num_field
,
648 build (PLUS_EXPR
, TREE_TYPE (num_field
),
649 num_field
, build_int_2 (1, 0)));
650 TREE_SIDE_EFFECTS (t
) = 1;
651 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
656 /* Return truth value of whether OP can be used as an word register
657 operand. Reject (SUBREG:SI (REG:SF )) */
660 int_reg_operand (op
, mode
)
662 enum machine_mode mode
;
664 return (register_operand (op
, mode
) &&
665 (GET_CODE (op
) != SUBREG
||
666 GET_MODE_CLASS (GET_MODE (SUBREG_REG (op
))) == MODE_INT
));
669 /* Return truth value of whether OP can be used as a float register
670 operand. Reject (SUBREG:SF (REG:SI )) )) */
673 fp_reg_operand (op
, mode
)
675 enum machine_mode mode
;
677 return (register_operand (op
, mode
) &&
678 (GET_CODE (op
) != SUBREG
||
679 GET_MODE_CLASS (GET_MODE (SUBREG_REG (op
))) == MODE_FLOAT
));