/* Definitions of target machine for GNU compiler.  amiga 68000/68020 version.
   Copyright (C) 1992 Free Software Foundation, Inc.
   Contributed by Markus M. Wild (wild@amiga.physik.unizh.ch).

This file is part of GNU CC.

GNU CC 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.

GNU CC 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 GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Phil.B 12-Mar-95: Define USE_GAS if GCC is supposed to work with the GNU
   assembler, GNU linker and GNU debugger using DBX debugging information. */

#define USE_GAS

/* Control assembler-syntax conditionals in m68k.md.  */

#ifndef USE_GAS
#define MOTOROLA		/* Use Motorola syntax rather than "MIT" */
#endif /* !USE_GAS */

#include "m68k/m68k.h"

/* Enable some special Amiga only features.  FIXME: This define should
   be eliminated in favor of more general ways to enable the features. */

#define TARGET_AMIGAOS

/* See m68k.h for bits in TARGET_DEFAULT.
   0 means 68000, no hardware fpu (68881/68882/68040).
   7 means 68020 (or higher) with hardware fpu.  */

#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT 0
#endif

/* Define __HAVE_68881__ in preprocessor according to the -m flags.
   This will control the use of inline 68881 insns in certain macros.
   Also inform the program which CPU this is for.  */

#if TARGET_DEFAULT & 02

/* -m68881 is the default */
#define CPP_SPEC \
"%{!msoft-float:-D__HAVE_68881__ }\
%{!ansi:%{m68000:-Dmc68010}%{mc68000:-Dmc68010}%{m68030:-Dmc68030}%{mc68030:-Dmc68030}%{m68040:-Dmc68040}\
%{mc68040:-Dmc68040}%{!mc68000:%{!m68000:-Dmc68020}}}"

#else

/* -msoft-float is the default, assume -mc68000 as well */
#define CPP_SPEC \
  "%{m68881:-D__HAVE_68881__} " \
  "%{!ansi:" \
    "%{m68020:-Dmc68020} " \
    "%{mc68020:-Dmc68020} " \
    "%{m68020-40:-Dmc68020} " \
    "%{m68030:-Dmc68030} " \
    "%{m68040:-Dmc68040} " \
    "%{m68060:-Dmc68060} " \
    "%{!noixemul:-Dixemul}} " \
  "%{m68020:-D__mc68020__ -D__mc68020} " \
  "%{mc68020:-D__mc68020__ -D__mc68020} " \
  "%{m68020-40:-D__mc68020__ -D__mc68020} " \
  "%{m68030:-D__mc68030__ -D__mc68030} " \
  "%{m68040:-D__mc68040__ -D__mc68040} " \
  "%{m68060:-D__mc68060__ -D__mc68060} " \
  "%{!noixemul:-D__ixemul__ -D__ixemul} " \
  "%{malways-restore-a4:-Derrno=(*ixemul_errno)} " \
  "%{mrestore-a4:-Derrno=(*ixemul_errno)} "

/* Don't try using XFmode since we don't have appropriate runtime software
   support.  */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE 64

#endif

/* -m68000 requires special flags to the assembler.  */

#define ASM_SPEC "\
 %{m68000:-mc68010}\
 %{mc68000:-mc68010}\
 %{m68020:-mc68020}\
 %{mc68020:-mc68020}\
 %{m68030:-mc68030}\
 %{m68040:-mc68040}\
 %{m68060:-mc68060}\
 %{m68020-40:-mc68020}\
 %{!mc68000:%{!m68000:%{!mc68020:%{!m68020:%{!m68030:%{!m68040:%{!m68060:%{!m68020-40:-mc68010}}}}}}}}\
 %{msmall-code:-sc}\
"

/* amiga/amigaos are the new "standard" defines for the Amiga, MCH_AMIGA
 * was used before and is included for compatibility reasons.
 * "amigados" and "__amigados__" are obsolescent and will generate cpp warnings */

#define CPP_PREDEFINES "\
 -Dmc68000\
 -Damiga\
 -Damigaos\
 -Damigados\
 -DMCH_AMIGA\
 -DAMIGA\
 -D__chip=__attribute__((chip))\
 -D__saveds=__attribute__((saveds))\
 -D__interrupt=__attribute__((interrupt))\
 -D__stackext=__attribute__((stackext))\
 -D__regargs=__attribute__((regparm))\
 -D__stdargs=__attribute__((stkparm))\
 -D__aligned=__attribute__((aligned(4)))\
 -Asystem(amigaos)\
 -Asystem(amigados)\
 -Acpu(m68k)\
 -Amachine(m68k)\
"

/* Choose the right startup file, depending on whether we use base relative
   code, base relative code with automatic relocation (-resident), their large
   versions, libnix or plain crt0.o.  */

#define STARTFILE_SPEC \
  "%{!noixemul:" \
    "%{fbaserel:%{!resident:bcrt0.o%s}}" \
    "%{resident:rcrt0.o%s}" \
    "%{fbaserel32:%{!resident32:lcrt0.o%s}}" \
    "%{resident32:scrt0.o%s}" \
    "%{!resident:%{!fbaserel:%{!resident32:%{!fbaserel32:" \
      "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}}}}" \
  "%{noixemul:" \
    "%{resident:libnix/nrcrt0.o%s} " \
    "%{!resident:%{fbaserel:libnix/nbcrt0.o%s}%{!fbaserel:libnix/ncrt0.o%s}}} "

#define ENDFILE_SPEC "%{noixemul:-lstubs}"

/* Automatically search libamiga.a for AmigaOS specific functions.  Note
   that we first search the standard C library to resolve as much as
   possible from there, since it has names that are duplicated in libamiga.a
   which we *don't* want from there.  Then search libamiga.a for any calls
   that were not generated inline, and finally search the standard C library
   again to resolve any references that libamiga.a might have generated.
   This may only be a temporary solution since it might be better to simply
   remove the things from libamiga.a that should be pulled in from libc.a
   instead, which would eliminate the first reference to libc.a.  Note that
   if we don't search it automatically, it is very easy for the user to try
   to put in a -lamiga himself and get it in the wrong place, so that (for
   example) calls like sprintf come from -lamiga rather than -lc. */

#define LIB_SPEC "%{!noixemul:%{!p:%{!pg:-lc -lamiga -lc}}%{p:-lc_p}%{pg:-lc_p}}%{noixemul:-lnixmain -lnix -lamiga %{mstackcheck:-lstack} %{mstackextend:-lstack}}"

/* if debugging, tell the linker to output amiga-hunk symbols *and* a BSD
   compatible debug hunk (which will probably change in the future, it's not
   tremendously useful in its current state). */

#define LINK_SPEC \
  "%{noixemul:-fl libnix} " \
  "%{fbaserel:%{!resident:-m amiga_bss -fl libb}} " \
  "%{resident:-m amiga_bss -amiga-datadata-reloc -fl libb} " \
  "%{fbaserel32:%{!resident32:-m amiga_bss -fl libb32}} " \
  "%{resident32:-m amiga_bss -amiga-datadata-reloc -fl libb32} " \
  "%{g:-amiga-debug-hunk} " \
  "%{m68020:-fl libm020} " \
  "%{mc68020:-fl libm020} " \
  "%{m68030:-fl libm020} " \
  "%{m68040:-fl libm020} " \
  "%{m68060:-fl libm020} " \
  "%{m68020-40:-fl libm020} " \
  "%{m68881:-fl libm881} "

#define CC1_SPEC \
  "%{resident:-fbaserel} " \
  "%{resident32:-fbaserel32} " \
  "%{msmall-code:-fno-function-cse} "

/* Compile with stack extension.  */
#define MASK_STACKEXTEND 0x40000000
#define TARGET_STACKEXTEND (((target_flags & MASK_STACKEXTEND)		\
  && !lookup_attribute("interrupt",					\
    TYPE_ATTRIBUTES(TREE_TYPE(current_function_decl))))			\
  || lookup_attribute("stackext",					\
    TYPE_ATTRIBUTES(TREE_TYPE(current_function_decl))))

/* Compile with stack checking.  */
#define MASK_STACKCHECK 0x20000000
#define TARGET_STACKCHECK ((target_flags & MASK_STACKCHECK)		\
  && !(target_flags & MASK_STACKEXTEND)					\
  && !lookup_attribute("interrupt",					\
    TYPE_ATTRIBUTES(TREE_TYPE(current_function_decl)))			\
  && !lookup_attribute("stackext",					\
    TYPE_ATTRIBUTES(TREE_TYPE(current_function_decl))))

/* Compile with a4 restoring in public functions.  */
#define MASK_RESTORE_A4 0x10000000
#define TARGET_RESTORE_A4						\
  ((target_flags & MASK_RESTORE_A4) && TREE_PUBLIC(current_function_decl))

/* Compile with a4 restoring in all functions.  */
#define MASK_ALWAYS_RESTORE_A4 0x8000000
#define TARGET_ALWAYS_RESTORE_A4 (target_flags & MASK_ALWAYS_RESTORE_A4)

#ifndef MASK_REGPARM /* Will be defined in 2.8.0.  */
#define MASK_REGPARM 0x10
#endif

/* provide a dummy entry for the small-code switch. This is currently only
   needed by the assembler (explanations: m68k.h), but will be used by cc1
   to output 16bit pc-relative code later.
   PhB 21-Jun-95: use now SUBTARGET_SWITCHES instead of redefining
   whole TARGET_SWITCHES, means that all additions made to m68k.* are
   now taken into account */

#undef SUBTARGET_SWITCHES
#define SUBTARGET_SWITCHES  \
    { "small-code", 0 }, /* Affects *_SPEC and/or GAS.  */ \
    { "stackcheck", MASK_STACKCHECK},		\
    { "no-stackcheck", -MASK_STACKCHECK},	\
    { "stackextend", MASK_STACKEXTEND},		\
    { "no-stackextend", -MASK_STACKEXTEND},	\
    { "fixedstack", -(MASK_STACKCHECK | MASK_STACKEXTEND)}, \
    { "regparm", MASK_REGPARM},			\
    { "no-regparm", -MASK_REGPARM},		\
    { "restore-a4", MASK_RESTORE_A4},		\
    { "no-restore-a4", -MASK_RESTORE_A4},	\
    { "always-restore-a4", MASK_ALWAYS_RESTORE_A4}, \
    { "no-always-restore-a4", -MASK_ALWAYS_RESTORE_A4},

/* Every structure or union's size must be a multiple of 2 bytes.  */

/* #define STRUCTURE_SIZE_BOUNDARY 16 */

/* This is (almost;-)) BSD, so it wants DBX format.  */

#define DBX_DEBUGGING_INFO

/* Allow folding division by zero.  */
#define REAL_INFINITY

/* The following was hacked into final.c, to allow some notice of
 * source line and filename to be injected into the assembly code,
 * even if not using one of the "approved" debuggers (albaugh@agames.com).
 */
#if 0
#define ASM_NOTE_SOURCE_LINE(FILE, LINE, FILENAME)\
  fprintf(file,"*#line %d \"%s\"\n",(LINE),(FILENAME))
#endif

#if 0	/* This apparently is no longer necessary? */

/* This is how to output an assembler line defining a `double' constant.  */

#undef ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE)					\
  {									\
    if (REAL_VALUE_ISINF (VALUE))					\
      fprintf (FILE, "\t.double 0r%s99e999\n", (VALUE) > 0 ? "" : "-");	\
    else if (isnan (VALUE))						\
      {									\
	union { double d; long l[2];} t;				\
	t.d = (VALUE);							\
	fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", t.l[0], t.l[1]); \
      }									\
    else								\
      fprintf (FILE, "\t.double 0r%.17g\n", VALUE);			\
  }

/* This is how to output an assembler line defining a `float' constant.  */

#undef ASM_OUTPUT_FLOAT
#define ASM_OUTPUT_FLOAT(FILE,VALUE)					\
  {									\
    if (REAL_VALUE_ISINF (VALUE))					\
      fprintf (FILE, "\t.single 0r%s99e999\n", (VALUE) > 0 ? "" : "-");	\
    else if (isnan (VALUE))						\
      {									\
	union { float f; long l;} t;					\
	t.f = (VALUE);							\
	fprintf (FILE, "\t.long 0x%lx\n", t.l);				\
      }									\
    else								\
      fprintf (FILE, "\t.single 0r%.9g\n", VALUE);			\
  }

/* This is how to output an assembler lines defining floating operands.
   There's no way to output a NaN's fraction, so we lose it.  */
  
#undef ASM_OUTPUT_FLOAT_OPERAND
#define ASM_OUTPUT_FLOAT_OPERAND(CODE,FILE,VALUE)				\
 do {								\
      if (CODE == 'f')						\
        {							\
          (REAL_VALUE_ISINF ((VALUE))						\
           ? asm_fprintf (FILE, "%I0r%s99e999", ((VALUE) > 0 ? "" : "-")) \
           : (VALUE) == -0.0							\
           ? asm_fprintf (FILE, "%I0r-0.0")					\
           : asm_fprintf (FILE, "%I0r%.9g", (VALUE))) \
        } else {                                        \
          long l;						\
          REAL_VALUE_TO_TARGET_SINGLE (VALUE, l);		\
          if (sizeof (int) == sizeof (long))			\
            asm_fprintf ((FILE), "%I0x%x", l);			\
          else							\
            asm_fprintf ((FILE), "%I0x%lx", l);			\
        }							\
     } while (0)

#undef ASM_OUTPUT_DOUBLE_OPERAND
#define ASM_OUTPUT_DOUBLE_OPERAND(FILE,VALUE)				\
  (REAL_VALUE_ISINF ((VALUE))						\
   ? asm_fprintf (FILE, "%I0r%s99e999", ((VALUE) > 0 ? "" : "-")) \
   : (VALUE) == -0.0							\
   ? asm_fprintf (FILE, "%I0r-0.0")					\
   : asm_fprintf (FILE, "%I0r%.17g", (VALUE)))

#endif	/* 0 */

/* use A5 as framepointer instead of A6, this makes A6 available as a
   general purpose register, and can thus be used without problems in
   direct library calls. */

#undef FRAME_POINTER_REGNUM
#define FRAME_POINTER_REGNUM 13
#undef ARG_POINTER_REGNUM
#define ARG_POINTER_REGNUM 13

/* we use A4 for this, not A5, which is the framepointer */
#undef PIC_OFFSET_TABLE_REGNUM
#define PIC_OFFSET_TABLE_REGNUM 12

/* setup a default shell return value for those (gazillion..) programs that
   (inspite of ANSI-C) declare main() to be void (or even VOID...) and thus
   cause the shell to randomly caugh upon executing such programs (contrary
   to Unix, AmigaOS scripts are terminated with an error if a program returns
   with an error code above the `error' or even `failure' level
   (which is configurable with the FAILAT command) */

#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)

/* given that symbolic_operand(X), return TRUE if no special
   base relative relocation is necessary */

#define LEGITIMATE_BASEREL_OPERAND_P(X) \
  (flag_pic >= 3 && read_only_operand (X))

#undef LEGITIMATE_PIC_OPERAND_P
#define LEGITIMATE_PIC_OPERAND_P(X) \
  (! symbolic_operand (X, VOIDmode) || LEGITIMATE_BASEREL_OPERAND_P (X))

/* Phil.B 12-Mar-95: check if this would fix some PIC problems */
/* In m68k svr4, a symbol_ref rtx can be a valid PIC operand if it is an
   operand of a function call. */
/* #undef LEGITIMATE_PIC_OPERAND_P
#define LEGITIMATE_PIC_OPERAND_P(X) \
  (! symbolic_operand (X, VOIDmode) \
   || ((GET_CODE(X) == SYMBOL_REF) && SYMBOL_REF_FLAG(X)))
*/

/* Define this macro if references to a symbol must be treated
   differently depending on something about the variable or
   function named by the symbol (such as what section it is in).

   The macro definition, if any, is executed immediately after the
   rtl for DECL or other node is created.
   The value of the rtl will be a `mem' whose address is a
   `symbol_ref'.

   The usual thing for this macro to do is to a flag in the
   `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified
   name string in the `symbol_ref' (if one bit is not enough
   information).

   On the Amiga we use this to indicate if references to a symbol should be
   absolute or base relative.  */

#define ENCODE_SECTION_INFO(DECL)\
do									\
  {									\
    if (TREE_CODE (DECL) == FUNCTION_DECL)				\
      SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;			\
    else								\
      {									\
	rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'		\
		   ? TREE_CST_RTL (DECL) : DECL_RTL (DECL));		\
	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;				\
      }									\
  }									\
while (0)

/* according to varasm.c, RELOC referrs *only* to whether constants (!)
   are addressed by address. */

#undef SELECT_SECTION
#define SELECT_SECTION(DECL, RELOC)					\
{									\
  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))			\
	   && SYMBOL_REF_FLAG (XEXP ((TREE_CODE_CLASS (TREE_CODE (DECL))\
		!= 'd' ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)), 0)))	\
    readonly_data_section ();						\
  else									\
    data_section ();							\
}

/* Support sections in chip memory, currently '.datachip' only.  */
#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME) \
  fprintf ((FILE), "\t%s\n", (NAME))

/* GAS chokes on '.gcc_except_table'.  */
#define DONT_OUTPUT_EXCEPTION_SECTION

/* GAS supports alignment up to 32768 bytes.  */
#undef ASM_OUTPUT_ALIGN
#define ASM_OUTPUT_ALIGN(FILE, LOG)	\
  if ((LOG)==1)				\
    fprintf((FILE), "\t.even\n");	\
  else					\
    fprintf((FILE), "\t.align %d\n", (LOG));
#define MAX_OFILE_ALIGNMENT ((1 << 15)*BITS_PER_UNIT)

#undef WCHAR_TYPE
#define WCHAR_TYPE "unsigned int"

/*
 * Support for Amiga-specific variable and function attributes.
 * KI 11.02.96
 */

/* If defined, a C expression whose value is nonzero if IDENTIFIER
   with arguments ARGS is a valid machine specific attribute for DECL.
   The attributes in ATTRIBUTES have previously been assigned to DECL. */

#define VALID_MACHINE_DECL_ATTRIBUTE(decl, attributes, identifier, args) \
  (valid_amigaos_decl_attribute(decl, attributes, identifier, args))

/* If defined, a C expression whose value is nonzero if IDENTIFIER
   with arguments ARGS is a valid machine specific attribute for TYPE.
   The attributes in ATTRIBUTES have previously been assigned to TYPE. */

#define VALID_MACHINE_TYPE_ATTRIBUTE(type, attributes, identifier, args) \
  (valid_amigaos_type_attribute(type, attributes, identifier, args))

/* If defined, a C expression whose value is 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). */

#define COMP_TYPE_ATTRIBUTES(type1, type2) \
  (comp_amigaos_type_attributes(type1, type2))

/* Preserve the initial value of a4.  */

#define PROLOGUE_EXTRA_SAVE(mask, num_saved_regs)			\
  if (amigaos_restore_a4())						\
    {									\
      mask |= 1 << (15-PIC_OFFSET_TABLE_REGNUM);			\
      num_saved_regs++;							\
    }

/* Make a4 point at data hunk.  */

#define PROLOGUE_SET_PIC_REG(stream)					\
  if (flag_pic>=3)							\
    {									\
      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,%s\n",			\
	  reg_names[PIC_OFFSET_TABLE_REGNUM]);				\
    }

/* Restore the initial value of a4.  */

#define EPILOGUE_EXTRA_RESTORE(mask, nregs)				\
  if (amigaos_restore_a4())						\
    {									\
      mask |= 1 << PIC_OFFSET_TABLE_REGNUM;				\
      nregs++;								\
    }

/* If preserving a4, let the code generator know about it.  */

#undef SUBTARGET_INITIAL_FP_OFFSET
#define SUBTARGET_INITIAL_FP_OFFSET(offset)				\
  if (amigaos_restore_a4())						\
    offset+=4;

/* Determine if the epilogue should be output as RTL.  */

#undef USE_RETURN_INSN
#define USE_RETURN_INSN amigaos_use_return_insn()

/* Generate the test of d0 before return to set cc register in "interrupt"
   function.  */

#define EPILOGUE_EXTRA_TEST(stream)					\
  if (lookup_attribute("interrupt",					\
	TYPE_ATTRIBUTES(TREE_TYPE(current_function_decl))))		\
    asm_fprintf(stream, "\ttstl %R%s\n", reg_names[0])


/*
 * Support for automatic stack extension.
 */

#define HAVE_restore_stack_nonlocal 1
#define gen_restore_stack_nonlocal \
(TARGET_STACKEXTEND?gen_stack_cleanup_call:gen_move_insn)

#define HAVE_restore_stack_function 1
#define gen_restore_stack_function gen_restore_stack_nonlocal

#define HAVE_restore_stack_block 1
#define gen_restore_stack_block gen_restore_stack_nonlocal

/* Reserve PIC_OFFSET_TABLE_REGNUM (a4) for doing PIC relocation if position
   independent code is being generated, by making it a fixed register. */

#define CONDITIONAL_REGISTER_USAGE			\
{							\
  /* prevent saving/restoring of the base reg */	\
  if (flag_pic >= 3)					\
    {							\
      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;	\
      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;		\
    }							\
}

/* m68k.h defines this, which causes structures to be returned in static
   storage, resulting in nonreentrant code, which we don't want. */

#undef PCC_STATIC_STRUCT_RETURN

/*
 * Support for passing arguments in registers.
 */

extern char *amigaos_regparm_string;
extern int amigaos_regparm;

/* Custom structure used as "CUM" (see below).
   regsused: bitmask of registers already used.
   regnum: register number of recently passed argument, or -1 if passed on
     stack.
   numofregparm: number of registers in single class to be used to pass
     arguments. 0 for stack calls.
  formaltype: formal type of current argument (taken from function prototype).
    This is necessary for explicit register specification. */

struct amigaosargs
{
  long regsused;
  short regnum;
  short numofregparm;
  void *formaltype;
};

/* A C type for declaring a variable that is used as the first
   argument of `FUNCTION_ARG' and other related values. 

   We use our own structure "amigaosargs". */

#undef CUMULATIVE_ARGS
#define CUMULATIVE_ARGS struct amigaosargs

/* A C statement (sans semicolon) for initializing the variable CUM
   for the state at the beginning of the argument list. */

#undef INIT_CUMULATIVE_ARGS
#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME)	\
  (amigaos_init_cumulative_args(&(CUM), (FNTYPE), (LIBNAME)))

/* A C statement (sans semicolon) to update the summarizer variable
   CUM to advance past an argument in the argument list. */

#undef FUNCTION_ARG_ADVANCE
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)	\
  (amigaos_function_arg_advance(&(CUM), (MODE), (TYPE), (NAMED)))

/* A C expression that controls whether a function argument is passed
   in a register, and which register. */

#undef FUNCTION_ARG
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)		\
  ((struct rtx_def*)amigaos_function_arg(&(CUM), (MODE), (TYPE), (NAMED)))

/* A C expression for the number of words, at the beginning of an
   argument, must be put in registers.  The value must be zero for
   arguments that are passed entirely in registers or that are
   entirely pushed on the stack.

   We don't want any arguments to be passed partially in registers and
   partially on stack. */

#undef FUNCTION_ARG_PARTIAL_NREGS
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) (0)

/* A C expression that is nonzero if REGNO is the number of a hard
   register in which function arguments are sometimes passed.

   Using __attribute__ ((regparm))/-mregparm we can pass arguments in up to
   four first registers of each class.

   Explicitly, we can pass arguments in practically every register. The
   following macro "doesn't know" about it - making it accept all the
   registers resulted in "fixed or forbidden register was spilled" message
   during compilation of objc/sendmsg.c (__builtin_apply). This small "lie"
   shouldn't cause any troubles. */

#undef FUNCTION_ARG_REGNO_P
#define FUNCTION_ARG_REGNO_P(N)			\
  (((N)>=0 && (N)<4) || ((N)>=8 && (N)<12)	\
    || (TARGET_68881 && (N)>16 && (N)<20))

/* This macro is similar to `TARGET_SWITCHES' but defines names of
   command options that have values.  Its definition is an
   initializer with a subgrouping for each command option. */

#define TARGET_OPTIONS				\
{						\
  { "regparm=", &amigaos_regparm_string }	\
}

#undef SUBTARGET_OVERRIDE_OPTIONS
#define SUBTARGET_OVERRIDE_OPTIONS			\
{							\
  if (!TARGET_68020 && flag_pic==4)			\
    error("-fbaserel32 is not supported on the 68000 or 68010\n"); \
  if (amigaos_regparm_string)				\
  {							\
    amigaos_regparm=atoi(amigaos_regparm_string);	\
    if (amigaos_regparm<1 || amigaos_regparm>4)		\
      fatal ("-mregparm=%s is not between 1 and 4",	\
	amigaos_regparm_string);			\
  }							\
  if (TARGET_REGPARM)					\
    amigaos_regparm=2;					\
}

/* Used in cpp to do special handling on symbols found in #if,
   #ifdef, #ifndef, and #if defined directives.  Presently it just
   warns users not to test for obsolete "amigados" or "__amigados__" */

#define CPP_SYMNAME_HOOK(SYMNAME, SYMLENGTH)	\
do						\
  {						\
    char *symname=(SYMNAME);			\
    int symlength=(SYMLENGTH);			\
    if (symlength == 8 && strncmp(symname, "amigados", symlength) == 0 || \
	symlength == 12 && strncmp(symname, "__amigados__", symlength) == 0) \
      {						\
	char save = *(symname + symlength);	\
	*(symname + symlength) = '\000';	\
	warning ("change test for '%s' to use '__amigaos__' instead", symname); \
	warning ("this symbol will not be predefined in a future release"); \
	*(symname + symlength) = save;		\
      }						\
  }						\
while(0)

/* INITIALIZE_TRAMPOLINE is changed so that it clears the caches after
   writing instructions on the stack and before executing them. */

/* NOTE: part of this is copied from m68k.h */
#undef INITIALIZE_TRAMPOLINE
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)			     \
{									     \
  emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 2)), TRAMP);   \
  emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 18)), CXT);    \
  emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 22)), FNADDR); \
  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__flush_cache"),	     \
		     0, VOIDmode, 2, (TRAMP), Pmode,			     \
		     GEN_INT (TRAMPOLINE_SIZE), SImode);		     \
}

/*
 * Automatic dynamic linking support in collect2.
 */

/* This macro is used to check if all collect2 facilities should be used.
   We need a few special ones, like stripping after linking.  */

#define DO_COLLECTING (do_collecting || amigaos_do_collecting())

/* This macro is called in collect2 for every GCC argument name.
   ARG is a part of commandline (without '\0' at the end).  */

#define COLLECT2_GCC_OPTIONS_HOOK(ARG) amigaos_gccopts_hook(ARG)

/* This macro is called in collect2 for every ld's "-l" or "*.o" or "*.a"
   argument.  ARG is a complete argument, with '\0' at the end.  */

#define COLLECT2_LIBNAME_HOOK(ARG) amigaos_libname_hook(ARG)

/* This macro is called at collect2 exit, to clean everything up.  */

#define COLLECT2_EXTRA_CLEANUP amigaos_collect2_cleanup

/* This macro is called just before the first linker invocation.
   LD1_ARGV is "char** argv", which will be passed to "ld".  STRIP is an
   *address* of "strip_flag" variable.  */

#define COLLECT2_PRELINK_HOOK(LD1_ARGV, STRIP) \
amigaos_prelink_hook((LD1_ARGV), (STRIP))

/* This macro is called just after the first linker invocation, in place of
   "nm" and "ldd".  OUTPUT_FILE is the executable's filename.  */

#define COLLECT2_POSTLINK_HOOK(OUTPUT_FILE) amigaos_postlink_hook(OUTPUT_FILE)
