/* emx.c: Functions for emx as target system.

/* Written by Eberhard Mattes, based on i386.c.

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, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


#include <i386/i386.c>


/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
   attribute for TYPE.  The attributes in ATTRIBUTES have previously been
   assigned to TYPE.  */

int
emx_valid_type_attribute_p (type, attributes, identifier, args)
     tree type;
     tree attributes;
     tree identifier;
     tree args;
{
  if (TREE_CODE (type) != FUNCTION_TYPE
      && TREE_CODE (type) != FIELD_DECL
      && TREE_CODE (type) != TYPE_DECL)
    return 0;

  /* Stdcall attribute says callee is responsible for popping arguments
     if they are not variable.  */
  if (is_attribute_p ("stdcall", identifier))
    return (args == NULL_TREE);

  /* Cdecl attribute says the callee is a normal C declaration */
  if (is_attribute_p ("cdecl", identifier))
    return (args == NULL_TREE);

  if (is_attribute_p ("emxcall", identifier))
    return (args == NULL_TREE);

  if (is_attribute_p ("system", identifier))
    return (args == NULL_TREE);

  /* Regparm attribute specifies how many integer arguments are to be
     passed in registers */
  if (is_attribute_p ("regparm", identifier))
    {
      tree cst;

      if (!args || TREE_CODE (args) != TREE_LIST
	  || TREE_CHAIN (args) != NULL_TREE
	  || TREE_VALUE (args) == NULL_TREE)
	return 0;

      cst = TREE_VALUE (args);
      if (TREE_CODE (cst) != INTEGER_CST)
	return 0;

      if (TREE_INT_CST_HIGH (cst) != 0
	  || TREE_INT_CST_LOW (cst) < 0
	  || TREE_INT_CST_LOW (cst) > REGPARM_MAX)
	return 0;

      return 1;
    }

  return 0;
}


/* Value is the number of bytes of arguments automatically
   popped when returning from a subroutine call.
   FUNDECL is the declaration node of the function (as a tree),
   FUNTYPE is the data type of the function (as a tree),
   or for a library call it is an identifier node for the subroutine name.
   SIZE is the number of bytes of arguments passed on the stack.

   On the 80386, the RTD insn may be used to pop them if the number
   of args is fixed, but if the number is variable then the caller
   must pop them all.  RTD can't be used for library calls now
   because the library is compiled with the Unix compiler.
   Use of RTD is a selectable option, since it is incompatible with
   standard Unix calling sequences.  If the option is not selected,
   the caller must always pop the args.

   The attribute stdcall is equivalent to RTD on a per module basis.  */

int
emx_return_pops_args (fundecl, funtype, size)
     tree fundecl;
     tree funtype;
     int size;
{
  int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);

    /* Cdecl functions override -mrtd, and never pop the stack */
  if (!lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))
   && !lookup_attribute ("system", TYPE_ATTRIBUTES (funtype))
   && !lookup_attribute ("emxcall", TYPE_ATTRIBUTES (funtype)))
  {
    /* Stdcall functions will pop the stack if not variable args */
    if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
      rtd = 1;

    /* `optlink' functions taking a variable number of arguments
       should also pop the stack, but that's not implemented.
       We treat `optlink' functions taking a variable number of
       arguments like `system' functions.  */
    if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (funtype)))
      rtd = 1;

    if (rtd
        && (TYPE_ARG_TYPES (funtype) == NULL_TREE
	    || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)))
      return size;
  }

  /* Lose any fake structure return argument */
  /* @@@ This makes the generated code incompatible with that generated
   * by 2.7.2. I think this belongs in the if (rtd) ... case. Any ideas? */
  if (aggregate_value_p (TREE_TYPE (funtype)))
    return GET_MODE_SIZE (Pmode);

    return 0;
}
