1169689Skan/* Subroutines for insn-output.c for NetWare.
2169689Skan   Contributed by Jan Beulich (jbeulich@novell.com)
3169689Skan   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4169689Skan
5169689SkanThis file is part of GCC.
6169689Skan
7169689SkanGCC is free software; you can redistribute it and/or modify
8169689Skanit under the terms of the GNU General Public License as published by
9169689Skanthe Free Software Foundation; either version 2, or (at your option)
10169689Skanany later version.
11169689Skan
12169689SkanGCC is distributed in the hope that it will be useful,
13169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
14169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15169689SkanGNU General Public License for more details.
16169689Skan
17169689SkanYou should have received a copy of the GNU General Public License
18169689Skanalong with GCC; see the file COPYING.  If not, write to
19169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
20169689SkanBoston, MA 02110-1301, USA.  */
21169689Skan
22169689Skan#include "config.h"
23169689Skan#include "system.h"
24169689Skan#include "coretypes.h"
25169689Skan#include "tm.h"
26169689Skan#include "rtl.h"
27169689Skan#include "regs.h"
28169689Skan#include "hard-reg-set.h"
29169689Skan#include "output.h"
30169689Skan#include "tree.h"
31169689Skan#include "flags.h"
32169689Skan#include "tm_p.h"
33169689Skan#include "toplev.h"
34169689Skan#include "ggc.h"
35169689Skan
36169689Skan
37169689Skan/* Return string which is the former assembler name modified with an
38169689Skan   underscore prefix and a suffix consisting of an atsign (@) followed
39169689Skan   by the number of bytes of arguments */
40169689Skan
41169689Skanstatic tree
42169689Skangen_stdcall_or_fastcall_decoration (tree decl, char prefix)
43169689Skan{
44169689Skan  unsigned total = 0;
45169689Skan  /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
46169689Skan     of DECL_ASSEMBLER_NAME.  */
47169689Skan  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
48169689Skan  char *newsym;
49169689Skan  tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
50169689Skan
51169689Skan  if (formal_type != NULL_TREE)
52169689Skan    {
53169689Skan      /* These attributes are ignored for variadic functions in
54169689Skan	 i386.c:ix86_return_pops_args. For compatibility with MS
55169689Skan	 compiler do not add @0 suffix here.  */
56169689Skan      if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
57169689Skan	return NULL_TREE;
58169689Skan
59169689Skan      /* Quit if we hit an incomplete type.  Error is reported
60169689Skan	 by convert_arguments in c-typeck.c or cp/typeck.c.  */
61169689Skan      while (TREE_VALUE (formal_type) != void_type_node
62169689Skan	     && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
63169689Skan	{
64169689Skan	  unsigned parm_size
65169689Skan	    = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
66169689Skan
67169689Skan	  /* Must round up to include padding.  This is done the same
68169689Skan	     way as in store_one_arg.  */
69169689Skan	  parm_size = ((parm_size + PARM_BOUNDARY - 1)
70169689Skan		       / PARM_BOUNDARY * PARM_BOUNDARY);
71169689Skan	  total += parm_size;
72169689Skan	  formal_type = TREE_CHAIN (formal_type);
73169689Skan	}
74169689Skan    }
75169689Skan
76169689Skan  newsym = alloca (1 + strlen (asmname) + 1 + 10 + 1);
77169689Skan  return get_identifier_with_length (newsym,
78169689Skan				     sprintf (newsym,
79169689Skan					      "%c%s@%u",
80169689Skan					      prefix,
81169689Skan					      asmname,
82169689Skan					      total / BITS_PER_UNIT));
83169689Skan}
84169689Skan
85169689Skan/* Return string which is the former assembler name modified with an
86169689Skan   _n@ prefix where n represents the number of arguments passed in
87169689Skan   registers */
88169689Skan
89169689Skanstatic tree
90169689Skangen_regparm_prefix (tree decl, unsigned nregs)
91169689Skan{
92169689Skan  unsigned total = 0;
93169689Skan  /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
94169689Skan     of DECL_ASSEMBLER_NAME.  */
95169689Skan  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
96169689Skan  char *newsym;
97169689Skan  tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
98169689Skan
99169689Skan  if (formal_type != NULL_TREE)
100169689Skan    {
101169689Skan      /* This attribute is ignored for variadic functions.  */
102169689Skan      if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
103169689Skan	return NULL_TREE;
104169689Skan
105169689Skan      /* Quit if we hit an incomplete type.  Error is reported
106169689Skan	 by convert_arguments in c-typeck.c or cp/typeck.c.  */
107169689Skan      while (TREE_VALUE (formal_type) != void_type_node
108169689Skan	     && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
109169689Skan	{
110169689Skan	  unsigned parm_size
111169689Skan	    = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
112169689Skan
113169689Skan	  /* Must round up to include padding.  This is done the same
114169689Skan	     way as in store_one_arg.  */
115169689Skan	  parm_size = ((parm_size + PARM_BOUNDARY - 1)
116169689Skan		       / PARM_BOUNDARY * PARM_BOUNDARY);
117169689Skan	  total += parm_size;
118169689Skan	  formal_type = TREE_CHAIN (formal_type);
119169689Skan	}
120169689Skan    }
121169689Skan
122169689Skan  if (nregs > total / BITS_PER_WORD)
123169689Skan    nregs = total / BITS_PER_WORD;
124169689Skan  gcc_assert (nregs <= 9);
125169689Skan  newsym = alloca (3 + strlen (asmname) + 1);
126169689Skan  return get_identifier_with_length (newsym,
127169689Skan				     sprintf (newsym,
128169689Skan					      "_%u@%s",
129169689Skan					      nregs,
130169689Skan					      asmname));
131169689Skan}
132169689Skan
133169689Skanvoid
134169689Skani386_nlm_encode_section_info (tree decl, rtx rtl, int first)
135169689Skan{
136169689Skan  default_encode_section_info (decl, rtl, first);
137169689Skan
138169689Skan  if (first
139169689Skan      && TREE_CODE (decl) == FUNCTION_DECL
140169689Skan      && *IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) != '*'
141169689Skan      && !strchr (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), '@'))
142169689Skan    {
143169689Skan      tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
144169689Skan      tree newid;
145169689Skan
146169689Skan      if (lookup_attribute ("stdcall", type_attributes))
147169689Skan	newid = gen_stdcall_or_fastcall_decoration (decl, '_');
148169689Skan      else if (lookup_attribute ("fastcall", type_attributes))
149169689Skan	newid = gen_stdcall_or_fastcall_decoration (decl, FASTCALL_PREFIX);
150169689Skan      else if ((newid = lookup_attribute ("regparm", type_attributes)) != NULL_TREE)
151169689Skan	newid = gen_regparm_prefix (decl,
152169689Skan		      TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (newid))));
153169689Skan      if (newid != NULL_TREE)
154169689Skan	{
155169689Skan	  rtx rtlname = XEXP (rtl, 0);
156169689Skan
157169689Skan	  if (GET_CODE (rtlname) == MEM)
158169689Skan	    rtlname = XEXP (rtlname, 0);
159169689Skan	  XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
160169689Skan	  /* These attributes must be present on first declaration,
161169689Skan	     change_decl_assembler_name will warn if they are added
162169689Skan	     later and the decl has been referenced, but duplicate_decls
163169689Skan	     should catch the mismatch before this is called.  */
164169689Skan	  change_decl_assembler_name (decl, newid);
165169689Skan	}
166169689Skan    }
167169689Skan}
168169689Skan
169169689Skan/* Strip the stdcall/fastcall/regparm pre-/suffix.  */
170169689Skan
171169689Skanconst char *
172169689Skani386_nlm_strip_name_encoding (const char *str)
173169689Skan{
174169689Skan  const char *name = default_strip_name_encoding (str);
175169689Skan
176169689Skan  if (*str != '*' && (*name == '_' || *name == '@'))
177169689Skan    {
178169689Skan      const char *p = strchr (name + 1, '@');
179169689Skan
180169689Skan      if (p)
181169689Skan	{
182169689Skan	  ++name;
183169689Skan	  if (ISDIGIT (p[1]))
184169689Skan	    name = ggc_alloc_string (name, p - name);
185169689Skan	  else
186169689Skan	    {
187169689Skan	      gcc_assert (ISDIGIT (*name));
188169689Skan	      name++;
189169689Skan	      gcc_assert (name == p);
190169689Skan	    }
191169689Skan	}
192169689Skan    }
193169689Skan  return name;
194169689Skan}
195