diff options
Diffstat (limited to 'm68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c')
-rw-r--r-- | m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c | 1187 |
1 files changed, 461 insertions, 726 deletions
diff --git a/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c b/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c index 3b1782c..2c5cab1 100644 --- a/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c +++ b/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c @@ -1,726 +1,461 @@ -/* Configuration for GNU C-compiler for m68k Amiga, running AmigaOS.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2003
- Free Software Foundation, Inc.
- Contributed by Markus M. Wild (wild@amiga.physik.unizh.ch).
- Heavily modified by Kamil Iskra (iskra@student.uci.agh.edu.pl).
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-//work without flag_writable_strings which is not in GCC4
-//#include "config/m68k/amigaos.h"
-#define REGPARMS_68K 1
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "output.h"
-#include "tree.h"
-#include "flags.h"
-#include "expr.h"
-#include "toplev.h"
-#include "tm_p.h"
-
-static int amigaos_put_in_text (tree);
-static rtx gen_stack_management_call (rtx, rtx, const char *);
-int m68k_regparm;
-/* Baserel support. */
-
-/* Does operand (which is a symbolic_operand) live in text space? If
- so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true.
-
- This function is used in base relative code generation. */
-
-int
-read_only_operand (rtx operand)
-{
- if (GET_CODE (operand) == CONST)
- operand = XEXP (XEXP (operand, 0), 0);
- if (GET_CODE (operand) == SYMBOL_REF)
- return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
- return 1;
-}
-
-/* Choose the section to use for DECL. RELOC is true if its value contains
- any relocatable expression. */
-
-void
-amigaos_select_section (tree decl, int reloc,
- unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
-{
- // if (TREE_CODE (decl) == STRING_CST)
-// {
-//// flag_writable_strings /data_section not in gcc4,
-////make life easy and put to same section
-//// if (! flag_writable_strings)
-//// readonly_data_section ();
-//// else
-// //data_section ();
-// }
-// else if (TREE_CODE (decl) == VAR_DECL)
-// {
-// if (TREE_READONLY (decl)
-// && ! TREE_THIS_VOLATILE (decl)
-// && DECL_INITIAL (decl)
-// && (DECL_INITIAL (decl) == error_mark_node
-// || TREE_CONSTANT (DECL_INITIAL (decl)))
-// && (!flag_pic || (flag_pic<3 && !reloc)
-// || SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0))))
-// readonly_data_section ();
-// else
-// data_section ();
-// }
-// else if ((!flag_pic || (flag_pic<3 && !reloc)) && DECL_P(decl)
-// && SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)))
-// readonly_data_section ();
-// else
- //data_section ();
-}
-
-/* This function is used while generating a base relative code.
- It returns 1 if a decl is not relocatable, i. e., if it can be put
- in the text section.
- Currently, it's very primitive: it just checks if the object size
- is less than 4 bytes (i. e., if it can hold a pointer). It also
- supports arrays and floating point types. */
-
-static int
-amigaos_put_in_text (tree decl)
-{
- tree type = TREE_TYPE (decl);
- if (TREE_CODE (type) == ARRAY_TYPE)
- type = TREE_TYPE (type);
- return (TREE_INT_CST_HIGH (TYPE_SIZE (type)) == 0
- && TREE_INT_CST_LOW (TYPE_SIZE (type)) < 32)
- || FLOAT_TYPE_P (type);
-}
-
-/* Record properties of a DECL into the associated SYMBOL_REF. */
-
-void
-amigaos_encode_section_info (tree decl, rtx rtl, int first)
-{
- default_encode_section_info (decl, rtl, first);
-
-
- SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
- //if (TREE_CODE (decl) == FUNCTION_DECL) // huh seem do same. not in gcc4 flag_writable_strings
-// SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-// else
-// {
-// if ((RTX_UNCHANGING_P (rtl) && !MEM_VOLATILE_P (rtl)
-// && (flag_pic<3 || (TREE_CODE (decl) == STRING_CST
-// && !flag_writable_strings)
-// || amigaos_put_in_text (decl)))
-// || (TREE_CODE (decl) == VAR_DECL
-// && DECL_SECTION_NAME (decl) != NULL_TREE))
-// SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-// }
-}
-
-/* Common routine used to check if a4 should be preserved/restored. */
-
-int
-amigaos_restore_a4 (void)
-{
- return (flag_pic >= 3 &&
- (TARGET_RESTORE_A4 || TARGET_ALWAYS_RESTORE_A4
- || lookup_attribute ("saveds",
- TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))));
-}
-
-void
-amigaos_alternate_pic_setup (FILE *stream)
-{
- if (TARGET_RESTORE_A4 || TARGET_ALWAYS_RESTORE_A4)
- asm_fprintf (stream, "\tjbsr %U__restore_a4\n");
- else if (lookup_attribute ("saveds",
- TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
- asm_fprintf (stream, "\tlea %U__a4_init,%Ra4\n");
-}
-
-/* Attributes support. */
-
-#define AMIGA_CHIP_SECTION_NAME ".datachip"
-
-/* Handle a "chip" attribute;
- arguments as in struct attribute_spec.handler. */
-
-tree
-amigaos_handle_decl_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
-{
- if (TREE_CODE (*node) == VAR_DECL)
- {
- if (is_attribute_p ("chip", name))
-#ifdef TARGET_ASM_NAMED_SECTION
- {
- if (! TREE_STATIC (*node) && ! DECL_EXTERNAL (*node))
- error ("`chip' attribute cannot be specified for local variables");
- else
- {
- /* The decl may have already been given a section attribute from
- a previous declaration. Ensure they match. */
- if (DECL_SECTION_NAME (*node) == NULL_TREE)
- DECL_SECTION_NAME (*node) =
- build_string (strlen (AMIGA_CHIP_SECTION_NAME) + 1,
- AMIGA_CHIP_SECTION_NAME);
- else if (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (*node)),
- AMIGA_CHIP_SECTION_NAME) != 0)
- {
- error_with_decl (*node,
- "`chip' for `%s' conflicts with previous declaration");
- }
- }
- }
-#else
- error ("`chip' attribute is not supported for this target");
-#endif
- }
- else
- {
- warning ("`%s' attribute only applies to variables",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-//----- from 68k.c start
-
-
-
-
-
-/* Handle a "regparm" or "stkparm" attribute;
- arguments as in struct attribute_spec.handler. */
-
-
-static tree
-m68k_handle_type_attribute (tree *node, tree name, tree args,
- int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
-{
-
- if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE)
- {
- /* 'regparm' accepts one optional argument - number of registers in
- single class that should be used to pass arguments. */
- if (is_attribute_p ("regparm_x", name))
- {
- if (lookup_attribute ("stkparm_x", TYPE_ATTRIBUTES(*node)))
- {
- error ("`regparm' and `stkparm' are mutually exclusive");
- }
- if (args && TREE_CODE (args) == TREE_LIST)
- {
- tree numofregs = TREE_VALUE (args);
- if (numofregs)
- if (TREE_CODE (numofregs) != INTEGER_CST
-/*
- || compare_tree_int(numofregs, 1) < 0
- || compare_tree_int(numofregs, M68K_MAX_REGPARM) > 0)
-*/
- || TREE_INT_CST_HIGH (numofregs)
- || TREE_INT_CST_LOW (numofregs) < 1
- || TREE_INT_CST_LOW (numofregs) > M68K_MAX_REGPARM)
- {
- error ("invalid argument to `regparm' attribute");
- }
- }
- }
- else if (is_attribute_p ("stkparm_x", name))
- {
- if (lookup_attribute ("regparm_x", TYPE_ATTRIBUTES(*node)))
- {
- error ("`regparm' and `stkparm' are mutually exclusive");
- }
- }
- }
- else
- {
- warning ("`%s' attribute only applies to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Return zero if the attributes on TYPE1 and TYPE2 are incompatible,
- one if they are compatible, and two if they are nearly compatible
- (which causes a warning to be generated). */
-
-static int
-m68k_comp_type_attributes (tree type1, tree type2)
-{
-
- /* Functions or methods are incompatible if they specify mutually
- exclusive ways of passing arguments. */
- if (TREE_CODE (type1) == FUNCTION_TYPE || TREE_CODE (type1) == METHOD_TYPE)
- {
- tree arg1, arg2;
- if (!! lookup_attribute ("stkparm_x", TYPE_ATTRIBUTES (type1)) !=
- !! lookup_attribute ("stkparm_x", TYPE_ATTRIBUTES (type2))
- || !! lookup_attribute ("regparm_x", TYPE_ATTRIBUTES (type1)) !=
- !! lookup_attribute ("regparm_x", TYPE_ATTRIBUTES (type2)))
- return 0; /* 'regparm' and 'stkparm' are mutually exclusive. */
-
- arg1 = lookup_attribute ("regparm_x", TYPE_ATTRIBUTES (type1));
- arg2 = lookup_attribute ("regparm_x", TYPE_ATTRIBUTES (type2));
- if (arg1 && arg2)
- {
- int num1 = 0, num2 = 0;
- if (TREE_VALUE (arg1) && TREE_CODE (TREE_VALUE (arg1)) == TREE_LIST)
- {
- tree numofregs = TREE_VALUE (TREE_VALUE (arg1));
- if (numofregs)
- num1 = TREE_INT_CST_LOW (numofregs);
- }
- if (TREE_VALUE (arg2) && TREE_CODE (TREE_VALUE (arg2)) == TREE_LIST)
- {
- tree numofregs = TREE_VALUE (TREE_VALUE (arg2));
- if (numofregs)
- num2 = TREE_INT_CST_LOW (numofregs);
- }
- if (num1 != num2)
- return 0; /* Different numbers, or no number in one type. */
- }
- }
-#ifdef TARGET_AMIGAOS
- return amigaos_comp_type_attributes(type1, type2);
-#else
- return 1;
-#endif
-}
-
-/* Argument-passing support functions. */
-
-/* Initialize a variable CUM of type CUMULATIVE_ARGS
- for a call to a function whose data type is FNTYPE.
- For a library call, FNTYPE is 0. */
-
-void
-m68k_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype)
-{
- cum->last_arg_reg = -1;
- cum->regs_already_used = 0;
- if (fntype)
- {
- if (lookup_attribute ("stkparm_x", TYPE_ATTRIBUTES (fntype)))
- cum->num_of_regs = 0;
- else
- {
- tree ratree = lookup_attribute ("regparm_x", TYPE_ATTRIBUTES (fntype));
- if (ratree)
- {
- cum->num_of_regs = m68k_regparm ? m68k_regparm
- : M68K_DEFAULT_REGPARM;
- if (TREE_VALUE (ratree)
- && TREE_CODE (TREE_VALUE (ratree)) == TREE_LIST)
- {
- tree num_of_regs = TREE_VALUE (TREE_VALUE (ratree));
- cum->num_of_regs =
- num_of_regs ? TREE_INT_CST_LOW (num_of_regs) :
- (m68k_regparm ? m68k_regparm : M68K_DEFAULT_REGPARM);
- }
- }
- else
- cum->num_of_regs = m68k_regparm;
- }
- }
- else /* Libcall. */
- cum->num_of_regs = 0;
-
- if (cum->num_of_regs)
- {
- /* If this is a vararg call, put all arguments on stack. */
- tree param, next_param;
- for (param = TYPE_ARG_TYPES (fntype); param; param = next_param)
- {
- next_param = TREE_CHAIN (param);
- if (!next_param && TREE_VALUE (param) != void_type_node)
- cum->num_of_regs = 0;
- }
- }
-
-#if ! defined (PCC_STATIC_STRUCT_RETURN) && defined (M68K_STRUCT_VALUE_REGNUM)
- /* If return value is a structure, and we pass the buffer address in a
- register, we can't use this register for our own purposes.
- FIXME: Something similar would be useful for static chain. */
- if (fntype && aggregate_value_p (TREE_TYPE (fntype), fntype))
- cum->regs_already_used |= (1 << M68K_STRUCT_VALUE_REGNUM);
-#endif
-}
-
-/* Update the data in CUM to advance over an argument. */
-
-void
-m68k_function_arg_advance (CUMULATIVE_ARGS *cum)
-{
- if (cum->last_arg_reg != -1)
- {
- int count;
- for (count = 0; count < cum->last_arg_len; count++)
- cum->regs_already_used |= (1 << (cum->last_arg_reg + count));
- cum->last_arg_reg = -1;
- }
-}
-
-/* Define where to put the arguments to a function.
- Value is zero to push the argument on the stack,
- or a hard register in which to store the argument.
-
- MODE is the argument's machine mode.
- TYPE is the data type of the argument (as a tree).
- This is null for libcalls where that information may
- not be available.
- CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called. */
-
-struct rtx_def *
-m68k_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type)
-{
- if (cum->num_of_regs)
- {
- int regbegin = -1, altregbegin = -1, len;
-
- /* FIXME: The last condition below is a workaround for a bug. */
- if (TARGET_68881 && FLOAT_MODE_P (mode) &&
- GET_MODE_UNIT_SIZE (mode) <= 12 &&
- (GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT || mode == SCmode))
- {
- regbegin = 16; /* FPx */
- len = GET_MODE_NUNITS (mode);
- }
- /* FIXME: Two last conditions below are workarounds for bugs. */
- else if (INTEGRAL_MODE_P (mode) && mode !=CQImode && mode != CHImode)
- {
- if (POINTER_TYPE_P (type))
- regbegin = 8; /* Ax */
- else
- regbegin = 0; /* Dx */
- altregbegin = 8 - regbegin;
- len = (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
- }
-
- if (regbegin != -1)
- {
- int reg;
- long mask;
-
-look_for_reg:
- mask = 1 << regbegin;
- for (reg = 0; reg < cum->num_of_regs; reg++, mask <<= 1)
- if (!(cum->regs_already_used & mask))
- {
- int end;
- for (end = reg; end < cum->num_of_regs && end < reg + len;
- end++, mask <<= 1)
- if (cum->regs_already_used & mask)
- break;
- if (end == reg + len)
- {
- cum->last_arg_reg = reg + regbegin;
- cum->last_arg_len = len;
- break;
- }
- }
-
- if (reg == cum->num_of_regs && altregbegin != -1)
- {
- regbegin = altregbegin;
- altregbegin = -1;
- goto look_for_reg;
- }
- }
-
- if (cum->last_arg_reg != -1)
- return gen_rtx_REG (mode, cum->last_arg_reg);
- }
- return 0;
-}
-
-// end from 68k.h diff
-
-/* Handle a "stackext", "interrupt" or "saveds" attribute;
-+ arguments as in struct attribute_spec.handler. */
-
-tree
-amigaos_handle_type_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
-{
- if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE)
- {
- if (is_attribute_p ("stackext", name))
- {
- if (lookup_attribute ("interrupt", TYPE_ATTRIBUTES(*node)))
- {
- error ("`stackext' and `interrupt' are mutually exclusive");
- }
- }
- else if (is_attribute_p ("interrupt", name))
- {
- if (lookup_attribute ("stackext", TYPE_ATTRIBUTES(*node)))
- {
- error ("`stackext' and `interrupt' are mutually exclusive");
- }
- }
- else if (is_attribute_p ("saveds", name))
- {
- }
- }
- else
- {
- warning ("`%s' attribute only applies to functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
- }
-
- return NULL_TREE;
-}
-
-/* Stack checking and automatic extension support. */
-
-void
-amigaos_prologue_begin_hook (FILE *stream, int fsize)
-{
- if (TARGET_STACKCHECK)
- {
- if (fsize < 256)
- asm_fprintf (stream, "\tcmpl %s,%Rsp\n"
- "\tjcc 0f\n"
- "\tjra %U__stkovf\n"
- "\t0:\n",
- (flag_pic == 3 ? "a4@(___stk_limit:W)" :
- (flag_pic == 4 ? "a4@(___stk_limit:L)" :
- "___stk_limit")));
- else
- asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__stkchk_d0\n",
- fsize);
- }
-}
-
-void
-amigaos_alternate_frame_setup_f (FILE *stream, int fsize)
-{
- if (fsize < 128)
- asm_fprintf (stream, "\tcmpl %s,%Rsp\n"
- "\tjcc 0f\n"
- "\tmoveq %I%d,%Rd0\n"
- "\tmoveq %I0,%Rd1\n"
- "\tjbsr %U__stkext_f\n"
- "0:\tlink %Ra5,%I%d:W\n",
- (flag_pic == 3 ? "a4@(___stk_limit:W)" :
- (flag_pic == 4 ? "a4@(___stk_limit:L)" :
- "___stk_limit")),
- fsize, -fsize);
- else
- asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__link_a5_d0_f\n",
- fsize);
-}
-
-void
-amigaos_alternate_frame_setup (FILE *stream, int fsize)
-{
- if (!fsize)
- asm_fprintf (stream, "\tcmpl %s,%Rsp\n"
- "\tjcc 0f\n"
- "\tmoveq %I0,%Rd0\n"
- "\tmoveq %I0,%Rd1\n"
- "\tjbsr %U__stkext_f\n"
- "0:\n",
- (flag_pic == 3 ? "a4@(___stk_limit:W)" :
- (flag_pic == 4 ? "a4@(___stk_limit:L)" :
- "___stk_limit")));
- else if (fsize < 128)
- asm_fprintf (stream, "\tcmpl %s,%Rsp\n"
- "\tjcc 0f\n"
- "\tmoveq %I%d,%Rd0\n"
- "\tmoveq %I0,%Rd1\n"
- "\tjbsr %U__stkext_f\n"
- "0:\taddw %I%d,%Rsp\n",
- (flag_pic == 3 ? "a4@(___stk_limit:W)" :
- (flag_pic == 4 ? "a4@(___stk_limit:L)" :
- "___stk_limit")),
- fsize, -fsize);
- else
- asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__sub_d0_sp_f\n",
- fsize);
-}
-
-//static rtx
-//gen_stack_management_call (rtx stack_pointer, rtx arg, const char *func)
-//{
-// rtx call_insn, call, seq, name;
-// start_sequence ();
-//
-// /* Move arg to d0. */
-// emit_move_insn (gen_rtx_REG (SImode, 0), arg);
-//
-// /* Generate the function reference. */
-// name = gen_rtx_SYMBOL_REF (Pmode, func);
-// SYMBOL_REF_FLAG (name) = 1;
-// /* If optimizing, put it in a psedo so that several loads can be merged
-// into one. */
-// if (optimize && ! flag_no_function_cse)
-// name = copy_to_reg (name);
-//
-// /* Generate the function call. */
-// call = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (FUNCTION_MODE, name),
-// const0_rtx);
-// /* If we are doing stack extension, notify about the sp change. */
-// if (stack_pointer)
-// call = gen_rtx_SET (VOIDmode, stack_pointer, call);
-//
-// /* Generate the call instruction. */
-// call_insn = emit_call_insn (call);
-// /* Stack extension does not change memory in an unpredictable way. */
-// RTL_CONST_OR_PURE_CALL_P (call_insn) = 1;
-// /* We pass an argument in d0. */
-// CALL_INSN_FUNCTION_USAGE (call_insn) = gen_rtx_EXPR_LIST (VOIDmode,
-// gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 0)), 0);
-//
-// seq = get_insns ();
-// end_sequence ();
-// return seq;
-//}
-//
-//rtx
-//gen_stack_cleanup_call (rtx stack_pointer, rtx sa)
-//{
-// return gen_stack_management_call (stack_pointer, sa, "__move_d0_sp");
-//}
-//
-//void
-//amigaos_alternate_allocate_stack (rtx *operands)
-//{
-// if (TARGET_STACKEXTEND)
-// emit_insn (gen_stack_management_call (stack_pointer_rtx, operands[1],
-// "__sub_d0_sp"));
-// else
-// {
-// if (TARGET_STACKCHECK)
-// emit_insn (gen_stack_management_call (0, operands[1], "__stkchk_d0"));
-// anti_adjust_stack (operands[1]);
-// }
-// emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
-//}
-
-/* begin-GG-local: explicit register specification for parameters */
-
-/* Initialize a variable CUM of type CUMULATIVE_ARGS
- for a call to a function whose data type is FNTYPE.
- For a library call, FNTYPE is 0. */
-
-void
-amigaos_init_cumulative_args(CUMULATIVE_ARGS *cum, tree fntype)
-{
- m68k_init_cumulative_args(cum, fntype);
-
- if (fntype)
- cum->formal_type=TYPE_ARG_TYPES(fntype);
- else /* Call to compiler-support function. */
- cum->formal_type=0;
-}
-
-/* Update the data in CUM to advance over an argument. */
-
-void
-amigaos_function_arg_advance(CUMULATIVE_ARGS *cum)
-{
- m68k_function_arg_advance(cum);
-
- if (cum->formal_type)
- cum->formal_type=TREE_CHAIN((tree)cum->formal_type);
-}
-
-/* A C expression that controls whether a function argument is passed
- in a register, and which register. */
-
-struct rtx_def *
-amigaos_function_arg(CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type)
-{
- tree asmtree;
- return m68k_function_arg(cum, mode, type); // use old routine
- if (cum->formal_type && TREE_VALUE((tree)cum->formal_type)
- && (asmtree=lookup_attribute("asm_x",
- TYPE_ATTRIBUTES(TREE_VALUE((tree)cum->formal_type)))))
- {
- int i;
-#if 0
- /* See c-decl.c/push_parm_decl for an explanation why this doesn't work.
- */
- cum->last_arg_reg=TREE_INT_CST_LOW(TREE_VALUE(TREE_VALUE(asmtree)));
-#else
- cum->last_arg_reg=TREE_INT_CST_LOW(TREE_VALUE(asmtree));
-#endif
- cum->last_arg_len=HARD_REGNO_NREGS(cum->last_arg_reg, mode);
-
- for (i=0; i<cum->last_arg_len; i++)
- if (cum->regs_already_used & (1 << cum->last_arg_reg+i))
- {
- error("two parameters allocated for one register");
- break;
- }
- return gen_rtx_REG (mode, cum->last_arg_reg);
- }
- else
- return m68k_function_arg(cum, mode, type);
-}
-
-/* Return zero if the attributes on TYPE1 and TYPE2 are incompatible,
- one if they are compatible, and two if they are nearly compatible
- (which causes a warning to be generated). */
-
-int
-amigaos_comp_type_attributes (tree type1, tree type2)
-{
- /* Functions or methods are incompatible if they specify mutually exclusive
- ways of passing arguments. */
- if (TREE_CODE(type1)==FUNCTION_TYPE || TREE_CODE(type1)==METHOD_TYPE)
- {
- tree arg1, arg2;
- arg1=TYPE_ARG_TYPES(type1);
- arg2=TYPE_ARG_TYPES(type2);
- for (; arg1 && arg2; arg1=TREE_CHAIN(arg1), arg2=TREE_CHAIN(arg2))
- if (TREE_VALUE(arg1) && TREE_VALUE(arg2))
- {
- tree asm1, asm2;
- asm1=lookup_attribute("asm_x", TYPE_ATTRIBUTES(TREE_VALUE(arg1)));
- asm2=lookup_attribute("asm_x", TYPE_ATTRIBUTES(TREE_VALUE(arg2)));
- if (asm1 && asm2)
- {
- if (TREE_INT_CST_LOW(TREE_VALUE(asm1))!=
- TREE_INT_CST_LOW(TREE_VALUE(asm2)))
- return 0; /* Two different registers specified. */
- }
- else
- if (asm1 || asm2)
- return 0; /* "asm" used in only one type. */
- }
- }
- return 1;
-}
-
-/* end-GG-local */
+/* Configuration for GNU C-compiler for m68k Amiga, running AmigaOS. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2003 + Free Software Foundation, Inc. + Contributed by Markus M. Wild (wild@amiga.physik.unizh.ch). + Heavily modified by Kamil Iskra (iskra@student.uci.agh.edu.pl). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "output.h" +#include "tree.h" +#include "flags.h" +#include "expr.h" +#include "toplev.h" +#include "tm_p.h" + +static int amigaos_put_in_text (tree); +static rtx gen_stack_management_call (rtx, rtx, const char *); + +/* Baserel support. */ + +/* Does operand (which is a symbolic_operand) live in text space? If + so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true. + + This function is used in base relative code generation. */ + +int +read_only_operand (rtx operand) +{ + if (GET_CODE (operand) == CONST) + operand = XEXP (XEXP (operand, 0), 0); + if (GET_CODE (operand) == SYMBOL_REF) + return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand); + return 1; +} + +/* Choose the section to use for DECL. RELOC is true if its value contains + any relocatable expression. */ + +void +amigaos_select_section (tree decl, int reloc, + unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (decl) == STRING_CST) + { + if (! flag_writable_strings) + readonly_data_section (); + else + data_section (); + } + else if (TREE_CODE (decl) == VAR_DECL) + { + if (TREE_READONLY (decl) + && ! TREE_THIS_VOLATILE (decl) + && DECL_INITIAL (decl) + && (DECL_INITIAL (decl) == error_mark_node + || TREE_CONSTANT (DECL_INITIAL (decl))) + && (!flag_pic || (flag_pic<3 && !reloc) + || SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)))) + readonly_data_section (); + else + data_section (); + } + else if ((!flag_pic || (flag_pic<3 && !reloc)) && DECL_P(decl) + && SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0))) + readonly_data_section (); + else + data_section (); +} + +/* This function is used while generating a base relative code. + It returns 1 if a decl is not relocatable, i. e., if it can be put + in the text section. + Currently, it's very primitive: it just checks if the object size + is less than 4 bytes (i. e., if it can hold a pointer). It also + supports arrays and floating point types. */ + +static int +amigaos_put_in_text (tree decl) +{ + tree type = TREE_TYPE (decl); + if (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + return (TREE_INT_CST_HIGH (TYPE_SIZE (type)) == 0 + && TREE_INT_CST_LOW (TYPE_SIZE (type)) < 32) + || FLOAT_TYPE_P (type); +} + +/* Record properties of a DECL into the associated SYMBOL_REF. */ + +void +amigaos_encode_section_info (tree decl, rtx rtl, int first) +{ + default_encode_section_info (decl, rtl, first); + + if (TREE_CODE (decl) == FUNCTION_DECL) + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; + else + { + if ((RTX_UNCHANGING_P (rtl) && !MEM_VOLATILE_P (rtl) + && (flag_pic<3 || (TREE_CODE (decl) == STRING_CST + && !flag_writable_strings) + || amigaos_put_in_text (decl))) + || (TREE_CODE (decl) == VAR_DECL + && DECL_SECTION_NAME (decl) != NULL_TREE)) + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; + } +} + +/* Common routine used to check if a4 should be preserved/restored. */ + +int +amigaos_restore_a4 (void) +{ + return (flag_pic >= 3 && + (TARGET_RESTORE_A4 || TARGET_ALWAYS_RESTORE_A4 + || lookup_attribute ("saveds", + TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))); +} + +void +amigaos_alternate_pic_setup (FILE *stream) +{ + if (TARGET_RESTORE_A4 || TARGET_ALWAYS_RESTORE_A4) + asm_fprintf (stream, "\tjbsr %U__restore_a4\n"); + else if (lookup_attribute ("saveds", + TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) + asm_fprintf (stream, "\tlea %U__a4_init,%Ra4\n"); +} + +/* Attributes support. */ + +#define AMIGA_CHIP_SECTION_NAME ".datachip" + +/* Handle a "chip" attribute; + arguments as in struct attribute_spec.handler. */ + +tree +amigaos_handle_decl_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == VAR_DECL) + { + if (is_attribute_p ("chip", name)) +#ifdef TARGET_ASM_NAMED_SECTION + { + if (! TREE_STATIC (*node) && ! DECL_EXTERNAL (*node)) + error ("`chip' attribute cannot be specified for local variables"); + else + { + /* The decl may have already been given a section attribute from + a previous declaration. Ensure they match. */ + if (DECL_SECTION_NAME (*node) == NULL_TREE) + DECL_SECTION_NAME (*node) = + build_string (strlen (AMIGA_CHIP_SECTION_NAME) + 1, + AMIGA_CHIP_SECTION_NAME); + else if (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (*node)), + AMIGA_CHIP_SECTION_NAME) != 0) + { + error_with_decl (*node, + "`chip' for `%s' conflicts with previous declaration"); + } + } + } +#else + error ("`chip' attribute is not supported for this target"); +#endif + } + else + { + warning ("`%s' attribute only applies to variables", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "stackext", "interrupt" or "saveds" attribute; + arguments as in struct attribute_spec.handler. */ + +tree +amigaos_handle_type_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_TYPE || TREE_CODE (*node) == METHOD_TYPE) + { + if (is_attribute_p ("stackext", name)) + { + if (lookup_attribute ("interrupt", TYPE_ATTRIBUTES(*node))) + { + error ("`stackext' and `interrupt' are mutually exclusive"); + } + } + else if (is_attribute_p ("interrupt", name)) + { + if (lookup_attribute ("stackext", TYPE_ATTRIBUTES(*node))) + { + error ("`stackext' and `interrupt' are mutually exclusive"); + } + } + else if (is_attribute_p ("saveds", name)) + { + } + } + else + { + warning ("`%s' attribute only applies to functions", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Stack checking and automatic extension support. */ + +void +amigaos_prologue_begin_hook (FILE *stream, int fsize) +{ + if (TARGET_STACKCHECK) + { + if (fsize < 256) + asm_fprintf (stream, "\tcmpl %s,%Rsp\n" + "\tjcc 0f\n" + "\tjra %U__stkovf\n" + "\t0:\n", + (flag_pic == 3 ? "a4@(___stk_limit:W)" : + (flag_pic == 4 ? "a4@(___stk_limit:L)" : + "___stk_limit"))); + else + asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__stkchk_d0\n", + fsize); + } +} + +void +amigaos_alternate_frame_setup_f (FILE *stream, int fsize) +{ + if (fsize < 128) + asm_fprintf (stream, "\tcmpl %s,%Rsp\n" + "\tjcc 0f\n" + "\tmoveq %I%d,%Rd0\n" + "\tmoveq %I0,%Rd1\n" + "\tjbsr %U__stkext_f\n" + "0:\tlink %Ra5,%I%d:W\n", + (flag_pic == 3 ? "a4@(___stk_limit:W)" : + (flag_pic == 4 ? "a4@(___stk_limit:L)" : + "___stk_limit")), + fsize, -fsize); + else + asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__link_a5_d0_f\n", + fsize); +} + +void +amigaos_alternate_frame_setup (FILE *stream, int fsize) +{ + if (!fsize) + asm_fprintf (stream, "\tcmpl %s,%Rsp\n" + "\tjcc 0f\n" + "\tmoveq %I0,%Rd0\n" + "\tmoveq %I0,%Rd1\n" + "\tjbsr %U__stkext_f\n" + "0:\n", + (flag_pic == 3 ? "a4@(___stk_limit:W)" : + (flag_pic == 4 ? "a4@(___stk_limit:L)" : + "___stk_limit"))); + else if (fsize < 128) + asm_fprintf (stream, "\tcmpl %s,%Rsp\n" + "\tjcc 0f\n" + "\tmoveq %I%d,%Rd0\n" + "\tmoveq %I0,%Rd1\n" + "\tjbsr %U__stkext_f\n" + "0:\taddw %I%d,%Rsp\n", + (flag_pic == 3 ? "a4@(___stk_limit:W)" : + (flag_pic == 4 ? "a4@(___stk_limit:L)" : + "___stk_limit")), + fsize, -fsize); + else + asm_fprintf (stream, "\tmovel %I%d,%Rd0\n\tjbsr %U__sub_d0_sp_f\n", + fsize); +} + +static rtx +gen_stack_management_call (rtx stack_pointer, rtx arg, const char *func) +{ + rtx call_insn, call, seq, name; + start_sequence (); + + /* Move arg to d0. */ + emit_move_insn (gen_rtx_REG (SImode, 0), arg); + + /* Generate the function reference. */ + name = gen_rtx_SYMBOL_REF (Pmode, func); + SYMBOL_REF_FLAG (name) = 1; + /* If optimizing, put it in a psedo so that several loads can be merged + into one. */ + if (optimize && ! flag_no_function_cse) + name = copy_to_reg (name); + + /* Generate the function call. */ + call = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (FUNCTION_MODE, name), + const0_rtx); + /* If we are doing stack extension, notify about the sp change. */ + if (stack_pointer) + call = gen_rtx_SET (VOIDmode, stack_pointer, call); + + /* Generate the call instruction. */ + call_insn = emit_call_insn (call); + /* Stack extension does not change memory in an unpredictable way. */ + CONST_OR_PURE_CALL_P (call_insn) = 1; + /* We pass an argument in d0. */ + CALL_INSN_FUNCTION_USAGE (call_insn) = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 0)), 0); + + seq = get_insns (); + end_sequence (); + return seq; +} + +rtx +gen_stack_cleanup_call (rtx stack_pointer, rtx sa) +{ + return gen_stack_management_call (stack_pointer, sa, "__move_d0_sp"); +} + +void +amigaos_alternate_allocate_stack (rtx *operands) +{ + if (TARGET_STACKEXTEND) + emit_insn (gen_stack_management_call (stack_pointer_rtx, operands[1], + "__sub_d0_sp")); + else + { + if (TARGET_STACKCHECK) + emit_insn (gen_stack_management_call (0, operands[1], "__stkchk_d0")); + anti_adjust_stack (operands[1]); + } + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); +} + +/* begin-GG-local: explicit register specification for parameters */ + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. */ + +void +amigaos_init_cumulative_args(CUMULATIVE_ARGS *cum, tree fntype) +{ + m68k_init_cumulative_args(cum, fntype); + + if (fntype) + cum->formal_type=TYPE_ARG_TYPES(fntype); + else /* Call to compiler-support function. */ + cum->formal_type=0; +} + +/* Update the data in CUM to advance over an argument. */ + +void +amigaos_function_arg_advance(CUMULATIVE_ARGS *cum) +{ + m68k_function_arg_advance(cum); + + if (cum->formal_type) + cum->formal_type=TREE_CHAIN((tree)cum->formal_type); +} + +/* A C expression that controls whether a function argument is passed + in a register, and which register. */ + +struct rtx_def * +amigaos_function_arg(CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type) +{ + tree asmtree; + if (cum->formal_type && TREE_VALUE((tree)cum->formal_type) + && (asmtree=lookup_attribute("asm", + TYPE_ATTRIBUTES(TREE_VALUE((tree)cum->formal_type))))) + { + int i; +#if 0 + /* See c-decl.c/push_parm_decl for an explanation why this doesn't work. + */ + cum->last_arg_reg=TREE_INT_CST_LOW(TREE_VALUE(TREE_VALUE(asmtree))); +#else + cum->last_arg_reg=TREE_INT_CST_LOW(TREE_VALUE(asmtree)); +#endif + cum->last_arg_len=HARD_REGNO_NREGS(cum->last_arg_reg, mode); + + for (i=0; i<cum->last_arg_len; i++) + if (cum->regs_already_used & (1 << cum->last_arg_reg+i)) + { + error("two parameters allocated for one register"); + break; + } + return gen_rtx_REG (mode, cum->last_arg_reg); + } + else + return m68k_function_arg(cum, mode, type); +} + +/* Return zero if the attributes on TYPE1 and TYPE2 are incompatible, + one if they are compatible, and two if they are nearly compatible + (which causes a warning to be generated). */ + +int +amigaos_comp_type_attributes (tree type1, tree type2) +{ + /* Functions or methods are incompatible if they specify mutually exclusive + ways of passing arguments. */ + if (TREE_CODE(type1)==FUNCTION_TYPE || TREE_CODE(type1)==METHOD_TYPE) + { + tree arg1, arg2; + arg1=TYPE_ARG_TYPES(type1); + arg2=TYPE_ARG_TYPES(type2); + for (; arg1 && arg2; arg1=TREE_CHAIN(arg1), arg2=TREE_CHAIN(arg2)) + if (TREE_VALUE(arg1) && TREE_VALUE(arg2)) + { + tree asm1, asm2; + asm1=lookup_attribute("asm", TYPE_ATTRIBUTES(TREE_VALUE(arg1))); + asm2=lookup_attribute("asm", TYPE_ATTRIBUTES(TREE_VALUE(arg2))); + if (asm1 && asm2) + { + if (TREE_INT_CST_LOW(TREE_VALUE(asm1))!= + TREE_INT_CST_LOW(TREE_VALUE(asm2))) + return 0; /* Two different registers specified. */ + } + else + if (asm1 || asm2) + return 0; /* "asm" used in only one type. */ + } + } + return 1; +} + +/* end-GG-local */ |