/* Target definitions for GNU compiler for Intel x86 CPU running NeXTSTEP
   Copyright (C) 1993 Free Software Foundation, Inc.

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.  */

#include "i386/gas.h"
#include "nextstep.h"

/* By default, target has a 80387, with IEEE FP.  */

#undef	TARGET_DEFAULT
#define TARGET_DEFAULT  (1|0100)

/* Implicit library calls should use memcpy, not bcopy, etc.  */

#define TARGET_MEM_FUNCTIONS

/* Machines that use the AT&T assembler syntax
   also return floating point values in an FP register.
   Define how to find the value returned by a function.
   VALTYPE is the data type of the value (as a tree).
   If the precise function being called is known, FUNC is its FUNCTION_DECL;
   otherwise, FUNC is 0.  */

#undef	VALUE_REGNO
#define VALUE_REGNO(MODE) \
  ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode	\
   ? FIRST_FLOAT_REG : 0)

/* 1 if N is a possible register number for a function value. */

#undef	FUNCTION_VALUE_REGNO_P
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N)== FIRST_FLOAT_REG)

#ifdef REAL_VALUE_TO_TARGET_LONG_DOUBLE
#undef	ASM_OUTPUT_LONG_DOUBLE
#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE)				\
  do {									\
    long hex[3];							\
    REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, hex);			\
    if (sizeof (int) == sizeof (long))					\
      fprintf (FILE, "\t.long 0x%x\n\t.long 0x%x\n\t.long 0x%x\n",	\
		hex[0], hex[1], hex[2]);				\
    else								\
      fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n\t.long 0x%lx\n",	\
		hex[0], hex[1], hex[2]);				\
  } while (0)
#endif

#ifdef REAL_VALUE_TO_TARGET_DOUBLE
#undef	ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE)					\
  do {									\
    long hex[2];							\
    REAL_VALUE_TO_TARGET_DOUBLE (VALUE, hex);				\
    if (sizeof (int) == sizeof (long))					\
      fprintf (FILE, "\t.long 0x%x\n\t.long 0x%x\n", hex[0], hex[1]);	\
    else								\
      fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", hex[0], hex[1]);	\
  } while (0)
#endif

/* This is how to output an assembler line defining a `float' constant.  */

#ifdef REAL_VALUE_TO_TARGET_SINGLE
#undef	ASM_OUTPUT_FLOAT
#define ASM_OUTPUT_FLOAT(FILE,VALUE)					\
  do {									\
    long hex;								\
    REAL_VALUE_TO_TARGET_SINGLE (VALUE, hex);				\
    if (sizeof (int) == sizeof (long))					\
      fprintf (FILE, "\t.long 0x%x\n", hex);				\
    else								\
      fprintf (FILE, "\t.long 0x%lx\n", hex);				\
  } while (0)
#endif

/* A C statement or statements which output an assembler instruction
   opcode to the stdio stream STREAM.  The macro-operand PTR is a
   variable of type `char *' which points to the opcode name in its
   "internal" form--the form that is written in the machine description.

   GAS version 1.38.1 doesn't understand the `repz' opcode mnemonic.
   So use `repe' instead.  */

#undef	ASM_OUTPUT_OPCODE
#define ASM_OUTPUT_OPCODE(STREAM, PTR)	\
{							\
  if ((PTR)[0] == 'r'					\
      && (PTR)[1] == 'e'				\
      && (PTR)[2] == 'p')				\
    {							\
      if ((PTR)[3] == 'z')				\
	{						\
	  fprintf (STREAM, "repe");			\
	  (PTR) += 4;					\
	}						\
      else if ((PTR)[3] == 'n' && (PTR)[4] == 'z')	\
	{						\
	  fprintf (STREAM, "repne");			\
	  (PTR) += 5;					\
	}						\
    }							\
}

/* Define macro used to output shift-double opcodes when the shift
   count is in %cl.  Some assemblers require %cl as an argument;
   some don't.

   GAS requires the %cl argument, so override unx386.h. */

#undef	AS3_SHIFT_DOUBLE
#define AS3_SHIFT_DOUBLE(a,b,c,d) AS3 (a,b,c,d)

/* Print opcodes the way that GAS expects them. */
#define GAS_MNEMONICS 1

/* Names to predefine in the preprocessor for this target machine.  */

#undef	CPP_PREDEFINES
#define CPP_PREDEFINES "-Di386 -DNeXT -Dunix -D__MACH__ -D__LITTLE_ENDIAN__ -D__ARCHITECTURE__=\"i386\" -Asystem(unix) -Asystem(mach) -Acpu(i386) -Amachine(i386)"

/* This accounts for the return pc and saved fp on the i386. */

#define OBJC_FORWARDING_STACK_OFFSET 8
#define OBJC_FORWARDING_MIN_OFFSET 8

/* We do not want a dot in internal labels.  */

#undef LPREFIX
#define LPREFIX "L"

#undef	ASM_GENERATE_INTERNAL_LABEL
#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER)	\
    sprintf ((BUF), "*%s%d", (PREFIX), (NUMBER))

#undef ASM_OUTPUT_INTERNAL_LABEL
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM)	\
  fprintf (FILE, "%s%d:\n", PREFIX, NUM)

/* Output to assembler file text saying following lines
   may contain character constants, extra white space, comments, etc.  */

#undef	ASM_APP_ON
#define ASM_APP_ON "#APP\n"

/* Output to assembler file text saying following lines
   no longer contain unusual constructs.  */

#undef	ASM_APP_OFF
#define ASM_APP_OFF "#NO_APP\n"

#undef	ASM_OUTPUT_REG_PUSH
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO)  \
  fprintf (FILE, "\tpushl %se%s\n", "%", reg_names[REGNO])

#undef	ASM_OUTPUT_REG_POP
#define ASM_OUTPUT_REG_POP(FILE,REGNO)  \
  fprintf (FILE, "\tpopl %se%s\n", "%", reg_names[REGNO])

/* This is being overridden because the default i386 configuration
   generates calls to "_mcount".  NeXT system libraries all use
   "mcount".  */

#undef	FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO)				\
{									\
  if (flag_pic)								\
    {									\
      fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n",		\
               LPREFIX, (LABELNO));					\
      fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n");			\
    }									\
  else									\
    {								  	\
      fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO));	\
      fprintf (FILE, "\tcall mcount\n");				\
    }									\
}

/* BEGIN Calling Convention CHANGES */

/* These changes violate the Intel/Unix ABI.  Specifically, they
   change the way that space for a block return value is passed to a
   function.  The ABI says that the pointer is passed on the stack.
   We change to pass the pointer in %ebx.  This makes the NeXT
   Objective-C forwarding mechanism possible to implement on an i386.  */

/* Do NOT pass address of structure values on the stack.  */

#undef	STRUCT_VALUE_INCOMING
#undef	STRUCT_VALUE

/* Pass them in %ebx.  */

#undef	STRUCT_VALUE_REGNUM
#define STRUCT_VALUE_REGNUM 3

/* Because we are passing the pointer in a register, we don't need to
   rely on the callee to pop it.  */

#undef	RETURN_POPS_ARGS
#define RETURN_POPS_ARGS(FUNTYPE,SIZE) 				\
  (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE			\
   ? 0								\
   : (TARGET_RTD						\
      && (TYPE_ARG_TYPES (FUNTYPE) == 0				\
          || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE)))	\
              == void_type_node))) ? (SIZE) : 0)

/* END Calling Convention CHANGES */
