summaryrefslogtreecommitdiff
path: root/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c
diff options
context:
space:
mode:
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.c726
1 files changed, 726 insertions, 0 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
new file mode 100644
index 0000000..3b1782c
--- /dev/null
+++ b/m68k-unknown-amigaos/recipes/files/gcc/gcc/config/m68k/amigaos.c
@@ -0,0 +1,726 @@
+/* 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 */