1 /* Subroutines for insn-output.c for Clipper
2 Copyright (C) 1987, 1988, 1991, 1997, 1998, 1999, 2000, 2001
3 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"
32 #include "insn-attr.h"
43 #include "target-def.h"
45 static void clipper_output_function_prologue
PARAMS ((FILE *, HOST_WIDE_INT
));
46 static void clipper_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
47 static void clix_asm_out_constructor
PARAMS ((rtx
, int));
48 static void clix_asm_out_destructor
PARAMS ((rtx
, int));
50 extern char regs_ever_live
[];
52 extern int frame_pointer_needed
;
54 static int frame_size
;
56 /* Initialize the GCC target structure. */
57 #undef TARGET_ASM_FUNCTION_PROLOGUE
58 #define TARGET_ASM_FUNCTION_PROLOGUE clipper_output_function_prologue
59 #undef TARGET_ASM_FUNCTION_EPILOGUE
60 #define TARGET_ASM_FUNCTION_EPILOGUE clipper_output_function_epilogue
62 struct gcc_target targetm
= TARGET_INITIALIZER
;
64 /* Compute size of a clipper stack frame where 'lsize' is the required
65 space for local variables. */
68 clipper_frame_size (lsize
)
71 int i
, size
; /* total size of frame */
73 save_size
= 0; /* compute size for reg saves */
75 for (i
= 16; i
< 32; i
++)
76 if (regs_ever_live
[i
] && !call_used_regs
[i
])
79 for (i
= 0; i
< 16; i
++)
80 if (regs_ever_live
[i
] && !call_used_regs
[i
])
83 size
= lsize
+ save_size
;
85 size
= (size
+ 7) & ~7; /* align to 64 Bit */
89 /* Prologue and epilogue output
90 Function is entered with pc pushed, i.e. stack is 32 bit aligned
92 current_function_args_size == 0 means that the current function's args
93 are passed totally in registers i.e fp is not used as ap.
94 If frame_size is also 0 the current function does not push anything and
95 can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
99 clipper_output_function_prologue (file
, lsize
)
101 HOST_WIDE_INT lsize
; /* size for locals */
106 frame_size
= size
= clipper_frame_size (lsize
);
108 if (frame_pointer_needed
)
110 fputs ("\tpushw fp,sp\n", file
);
111 fputs ("\tmovw sp,fp\n", file
);
113 else if (size
!= 0 || current_function_args_size
!= 0)
115 size
+= 4; /* keep stack aligned */
116 frame_size
= size
; /* must push data or access args */
122 fprintf (file
, "\tsubq $%d,sp\n", size
);
124 fprintf (file
, "\tsubi $%d,sp\n", size
);
126 /* register save slots are relative to sp, because we have small positive
127 displacements and this works whether we have a frame pointer or not */
130 for (i
= 16; i
< 32; i
++)
131 if (regs_ever_live
[i
] && !call_used_regs
[i
])
134 fprintf (file
, "\tstord f%d,(sp)\n", i
-16);
136 fprintf (file
, "\tstord f%d,%d(sp)\n", i
-16, offset
);
140 for (i
= 0; i
< 16; i
++)
141 if (regs_ever_live
[i
] && !call_used_regs
[i
])
144 fprintf (file
, "\tstorw r%d,(sp)\n", i
);
146 fprintf (file
, "\tstorw r%d,%d(sp)\n", i
, offset
);
153 clipper_output_function_epilogue (file
, size
)
155 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
159 if (frame_pointer_needed
)
161 offset
= -frame_size
;
163 for (i
= 16; i
< 32; i
++)
164 if (regs_ever_live
[i
] && !call_used_regs
[i
])
166 fprintf (file
, "\tloadd %d(fp),f%d\n", offset
, i
-16);
170 for (i
= 0; i
< 16; i
++)
171 if (regs_ever_live
[i
] && !call_used_regs
[i
])
173 fprintf (file
, "\tloadw %d(fp),r%d\n", offset
, i
);
177 fputs ("\tmovw fp,sp\n\tpopw sp,fp\n\tret sp\n",
181 else /* no frame pointer */
185 for (i
= 16; i
< 32; i
++)
186 if (regs_ever_live
[i
] && !call_used_regs
[i
])
189 fprintf (file
, "\tloadd (sp),f%d\n", i
-16);
191 fprintf (file
, "\tloadd %d(sp),f%d\n", offset
, i
-16);
195 for (i
= 0; i
< 16; i
++)
196 if (regs_ever_live
[i
] && !call_used_regs
[i
])
199 fprintf (file
, "\tloadw (sp),r%d\n", i
);
201 fprintf (file
, "\tloadw %d(sp),r%d\n", offset
, i
);
208 fprintf (file
, "\taddq $%d,sp\n", frame_size
);
210 fprintf (file
, "\taddi $%d,sp\n", frame_size
);
213 fputs ("\tret sp\n", file
);
223 clipper_movstr (operands
)
226 rtx dst
,src
,cnt
,tmp
,top
,bottom
,xops
[3];
230 extern FILE *asm_out_file
;
234 /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
235 align
= INTVAL (operands
[3]);
239 if (GET_CODE (operands
[2]) == CONST_INT
) /* fixed size move */
241 if ((fixed
= INTVAL (operands
[2])) <= 0)
245 output_asm_insn ("loadq %2,%5", operands
);
247 output_asm_insn ("loadi %2,%5", operands
);
252 bottom
= (rtx
)gen_label_rtx (); /* need a bottom label */
253 xops
[0] = cnt
; xops
[1] = bottom
;
254 output_asm_insn ("movw %2,%5", operands
); /* count is scratch reg 5 */
255 output_asm_insn ("brle %l1", xops
);
259 top
= (rtx
)gen_label_rtx (); /* top of loop label */
260 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, "L", CODE_LABEL_NUMBER (top
));
263 xops
[0] = src
; xops
[1] = tmp
; xops
[2] = dst
;
265 if (fixed
&& (align
& 0x3) == 0) /* word aligned move with known size */
271 "loadw %a0,%1\n\taddq $4,%0\n\tstorw %1,%a2\n\taddq $4,%2",
274 xops1
[0] = cnt
; xops1
[1] = top
;
275 output_asm_insn ("subq $4,%0\n\tbrgt %l1", xops1
);
280 output_asm_insn ("loadh %a0,%1\n\tstorh %1,%a2", xops
);
282 output_asm_insn ("loadb 2%a0,%1\n\tstorb %1,2%a2", xops
);
286 output_asm_insn ("loadb %a0,%1\n\tstorb %1,%a2", xops
);
291 "loadb %a0,%1\n\taddq $1,%0\n\tstorb %1,%a2\n\taddq $1,%2",
294 xops
[0] = cnt
; xops
[1] = top
;
295 output_asm_insn ("subq $1,%0\n\tbrgt %l1", xops
);
299 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file
, "L", CODE_LABEL_NUMBER (bottom
));
304 print_operand_address (file
, addr
)
310 switch (GET_CODE (addr
))
313 fprintf (file
, "(%s)", reg_names
[REGNO (addr
)]);
317 /* can be 'symbol + reg' or 'reg + reg' */
319 op0
= XEXP (addr
, 0);
320 op1
= XEXP (addr
, 1);
322 if (GET_CODE (op0
) == REG
&& GET_CODE (op1
) == REG
)
324 fprintf (file
, "[%s](%s)",
325 reg_names
[REGNO (op0
)], reg_names
[REGNO (op1
)]);
329 if (GET_CODE (op0
) == REG
&& CONSTANT_ADDRESS_P (op1
))
331 output_addr_const (file
, op1
);
332 fprintf (file
, "(%s)", reg_names
[REGNO (op0
)]);
336 if (GET_CODE (op1
) == REG
&& CONSTANT_ADDRESS_P (op0
))
338 output_addr_const (file
, op0
);
339 fprintf (file
, "(%s)", reg_names
[REGNO (op1
)]);
342 abort (); /* Oh no */
345 output_addr_const (file
, addr
);
354 switch (GET_CODE (op
))
383 /* Dump the argument register to the stack; return the location
387 clipper_builtin_saveregs ()
389 rtx block
, addr
, r0_addr
, r1_addr
, f0_addr
, f1_addr
, mem
;
390 int set
= get_varargs_alias_set ();
392 /* Allocate the save area for r0,r1,f0,f1 */
394 block
= assign_stack_local (BLKmode
, 6 * UNITS_PER_WORD
, 2 * BITS_PER_WORD
);
396 RTX_UNCHANGING_P (block
) = 1;
397 RTX_UNCHANGING_P (XEXP (block
, 0)) = 1;
399 addr
= XEXP (block
, 0);
402 r1_addr
= plus_constant (addr
, 4);
403 f0_addr
= plus_constant (addr
, 8);
404 f1_addr
= plus_constant (addr
, 16);
408 mem
= gen_rtx_MEM (SImode
, r0_addr
);
409 set_mem_alias_set (mem
, set
);
410 emit_move_insn (mem
, gen_rtx_REG (SImode
, 0));
412 mem
= gen_rtx_MEM (SImode
, r1_addr
);
413 set_mem_alias_set (mem
, set
);
414 emit_move_insn (mem
, gen_rtx_REG (SImode
, 1));
416 /* Store float regs */
418 mem
= gen_rtx_MEM (DFmode
, f0_addr
);
419 set_mem_alias_set (mem
, set
);
420 emit_move_insn (mem
, gen_rtx_REG (DFmode
, 16));
422 mem
= gen_rtx_MEM (DFmode
, f1_addr
);
423 set_mem_alias_set (mem
, set
);
424 emit_move_insn (mem
, gen_rtx_REG (DFmode
, 17));
426 if (current_function_check_memory_usage
)
428 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
430 GEN_INT (GET_MODE_SIZE (DFmode
)),
431 TYPE_MODE (sizetype
),
432 GEN_INT (MEMORY_USE_RW
),
433 TYPE_MODE (integer_type_node
));
434 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
436 GEN_INT (GET_MODE_SIZE (DFmode
)),
437 TYPE_MODE (sizetype
),
438 GEN_INT (MEMORY_USE_RW
),
439 TYPE_MODE (integer_type_node
));
440 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
442 GEN_INT (GET_MODE_SIZE (SImode
)),
443 TYPE_MODE (sizetype
),
444 GEN_INT (MEMORY_USE_RW
),
445 TYPE_MODE (integer_type_node
));
446 emit_library_call (chkr_set_right_libfunc
, 1, VOIDmode
, 3,
448 GEN_INT (GET_MODE_SIZE (SImode
)),
449 TYPE_MODE (sizetype
),
450 GEN_INT (MEMORY_USE_RW
),
451 TYPE_MODE (integer_type_node
));
458 clipper_build_va_list ()
460 tree record
, ap
, reg
, num
;
465 int __va_ap; // pointer to stack args
466 void *__va_reg[4]; // pointer to r0,f0,r1,f1
467 int __va_num; // number of args processed
471 record
= make_node (RECORD_TYPE
);
473 num
= build_decl (FIELD_DECL
, get_identifier ("__va_num"),
475 DECL_FIELD_CONTEXT (num
) = record
;
477 reg
= build_decl (FIELD_DECL
, get_identifier ("__va_reg"),
478 build_array_type (ptr_type_node
,
479 build_index_type (build_int_2 (3, 0))));
480 DECL_FIELD_CONTEXT (reg
) = record
;
481 TREE_CHAIN (reg
) = num
;
483 ap
= build_decl (FIELD_DECL
, get_identifier ("__va_ap"),
485 DECL_FIELD_CONTEXT (ap
) = record
;
486 TREE_CHAIN (ap
) = reg
;
488 TYPE_FIELDS (record
) = ap
;
489 layout_type (record
);
495 clipper_va_start (stdarg_p
, valist
, nextarg
)
498 rtx nextarg ATTRIBUTE_UNUSED
;
500 tree ap_field
, reg_field
, num_field
;
501 tree t
, u
, save_area
;
503 ap_field
= TYPE_FIELDS (TREE_TYPE (valist
));
504 reg_field
= TREE_CHAIN (ap_field
);
505 num_field
= TREE_CHAIN (reg_field
);
507 ap_field
= build (COMPONENT_REF
, TREE_TYPE (ap_field
), valist
, ap_field
);
508 reg_field
= build (COMPONENT_REF
, TREE_TYPE (reg_field
), valist
, reg_field
);
509 num_field
= build (COMPONENT_REF
, TREE_TYPE (num_field
), valist
, num_field
);
511 /* Call __builtin_saveregs to save r0, r1, f0, and f1 in a block. */
513 save_area
= make_tree (integer_type_node
, expand_builtin_saveregs ());
517 t
= make_tree (ptr_type_node
, virtual_incoming_args_rtx
);
518 if (stdarg_p
&& current_function_args_info
.size
!= 0)
519 t
= build (PLUS_EXPR
, ptr_type_node
, t
,
520 build_int_2 (current_function_args_info
.size
, 0));
521 t
= build (MODIFY_EXPR
, TREE_TYPE (ap_field
), ap_field
, t
);
522 TREE_SIDE_EFFECTS (t
) = 1;
523 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
525 /* Set the four entries of __va_reg. */
527 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
528 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (0, 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 (8, 0)));
535 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
536 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (1, 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
);
541 t
= fold (build (PLUS_EXPR
, integer_type_node
, save_area
,
542 build_int_2 (4, 0)));
543 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
544 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (2, 0));
545 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
546 TREE_SIDE_EFFECTS (t
) = 1;
547 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
549 t
= fold (build (PLUS_EXPR
, integer_type_node
, save_area
,
550 build_int_2 (16, 0)));
551 t
= build1 (NOP_EXPR
, ptr_type_node
, save_area
);
552 u
= build (ARRAY_REF
, ptr_type_node
, reg_field
, build_int_2 (3, 0));
553 t
= build (MODIFY_EXPR
, ptr_type_node
, u
, t
);
554 TREE_SIDE_EFFECTS (t
) = 1;
555 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
559 t
= build_int_2 (current_function_args_info
.num
, 0);
560 t
= build (MODIFY_EXPR
, TREE_TYPE (num_field
), num_field
, t
);
561 TREE_SIDE_EFFECTS (t
) = 1;
562 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
566 clipper_va_arg (valist
, type
)
569 tree ap_field
, reg_field
, num_field
;
572 rtx addr_rtx
, over_label
= NULL_RTX
, tr
;
578 addr = VA.__va_reg[2 * VA.__va_num];
580 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
586 addr = VA.__va_reg[2 * VA.__va_num + 1];
588 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
593 addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE);
597 ap_field
= TYPE_FIELDS (TREE_TYPE (valist
));
598 reg_field
= TREE_CHAIN (ap_field
);
599 num_field
= TREE_CHAIN (reg_field
);
601 ap_field
= build (COMPONENT_REF
, TREE_TYPE (ap_field
), valist
, ap_field
);
602 reg_field
= build (COMPONENT_REF
, TREE_TYPE (reg_field
), valist
, reg_field
);
603 num_field
= build (COMPONENT_REF
, TREE_TYPE (num_field
), valist
, num_field
);
605 addr_rtx
= gen_reg_rtx (Pmode
);
607 if (! AGGREGATE_TYPE_P (type
))
612 over_label
= gen_label_rtx ();
613 false_label
= gen_label_rtx ();
615 emit_cmp_and_jump_insns (expand_expr (num_field
, NULL_RTX
, 0,
617 GEN_INT (2), GE
, const0_rtx
,
618 TYPE_MODE (TREE_TYPE (num_field
)),
619 TREE_UNSIGNED (num_field
), 0, false_label
);
621 inreg
= fold (build (MULT_EXPR
, integer_type_node
, num_field
,
622 build_int_2 (2, 0)));
623 if (FLOAT_TYPE_P (type
))
624 inreg
= fold (build (PLUS_EXPR
, integer_type_node
, inreg
,
625 build_int_2 (1, 0)));
626 inreg
= fold (build (ARRAY_REF
, ptr_type_node
, reg_field
, inreg
));
628 tr
= expand_expr (inreg
, addr_rtx
, VOIDmode
, EXPAND_NORMAL
);
630 emit_move_insn (addr_rtx
, tr
);
632 emit_jump_insn (gen_jump (over_label
));
634 emit_label (false_label
);
637 /* Round to alignment of `type', or at least integer alignment. */
639 align
= TYPE_ALIGN (type
);
640 if (align
< TYPE_ALIGN (integer_type_node
))
641 align
= TYPE_ALIGN (integer_type_node
);
642 align
/= BITS_PER_UNIT
;
644 addr
= fold (build (PLUS_EXPR
, ptr_type_node
, ap_field
,
645 build_int_2 (align
-1, 0)));
646 addr
= fold (build (BIT_AND_EXPR
, ptr_type_node
, addr
,
647 build_int_2 (-align
, -1)));
648 addr
= save_expr (addr
);
650 tr
= expand_expr (addr
, addr_rtx
, Pmode
, EXPAND_NORMAL
);
652 emit_move_insn (addr_rtx
, tr
);
654 t
= build (MODIFY_EXPR
, TREE_TYPE (ap_field
), ap_field
,
655 build (PLUS_EXPR
, TREE_TYPE (ap_field
),
656 addr
, build_int_2 (int_size_in_bytes (type
), 0)));
657 TREE_SIDE_EFFECTS (t
) = 1;
658 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
661 emit_label (over_label
);
663 t
= build (MODIFY_EXPR
, TREE_TYPE (num_field
), num_field
,
664 build (PLUS_EXPR
, TREE_TYPE (num_field
),
665 num_field
, build_int_2 (1, 0)));
666 TREE_SIDE_EFFECTS (t
) = 1;
667 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
672 /* Return truth value of whether OP can be used as an word register
673 operand. Reject (SUBREG:SI (REG:SF )) */
676 int_reg_operand (op
, mode
)
678 enum machine_mode mode
;
680 return (register_operand (op
, mode
) &&
681 (GET_CODE (op
) != SUBREG
||
682 GET_MODE_CLASS (GET_MODE (SUBREG_REG (op
))) == MODE_INT
));
685 /* Return truth value of whether OP can be used as a float register
686 operand. Reject (SUBREG:SF (REG:SI )) )) */
689 fp_reg_operand (op
, mode
)
691 enum machine_mode mode
;
693 return (register_operand (op
, mode
) &&
694 (GET_CODE (op
) != SUBREG
||
695 GET_MODE_CLASS (GET_MODE (SUBREG_REG (op
))) == MODE_FLOAT
));
699 clix_asm_out_constructor (symbol
, priority
)
701 int priority ATTRIBUTE_UNUSED
;
704 fputs ("\tloada ", asm_out_file
);
705 assemble_name (asm_out_file
, XSTR (symbol
, 0));
706 fputs (",r0\n\tsubq $8,sp\n\tstorw r0,(sp)\n", asm_out_file
);
710 clix_asm_out_destructor (symbol
, priority
)
712 int priority ATTRIBUTE_UNUSED
;
715 assemble_integer (symbol
, POINTER_SIZE
/ BITS_PER_UNIT
, POINTER_SIZE
, 1);
716 assemble_integer (const0_rtx
, POINTER_SIZE
/ BITS_PER_UNIT
, POINTER_SIZE
, 1);