OSDN Git Service

gcc/ChangeLog:
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / netware.c
1 /* Subroutines for insn-output.c for NetWare.
2    Contributed by Jan Beulich (jbeulich@novell.com)
3    Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "output.h"
29 #include "tree.h"
30 #include "flags.h"
31 #include "tm_p.h"
32 #include "toplev.h"
33 #include "langhooks.h"
34 #include "ggc.h"
35
36 /* Return string which is the function name, identified by ID, modified
37    with PREFIX and a suffix consisting of an atsign (@) followed by the
38    number of bytes of arguments.  If ID is NULL use the DECL_NAME as base.
39    Return NULL if no change required.  */
40
41 static tree
42 gen_stdcall_or_fastcall_decoration (tree decl, tree id, char prefix)
43 {
44   unsigned HOST_WIDE_INT total = 0;
45   const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
46   char *new_str;
47   tree type = TREE_TYPE (decl);
48
49   if (prototype_p (type))
50     {
51       tree arg;
52       function_args_iterator args_iter;
53
54       /* This attribute is ignored for variadic functions.  */ 
55       if (stdarg_p (type))
56         return NULL_TREE;
57
58       /* Quit if we hit an incomplete type.  Error is reported
59          by convert_arguments in c-typeck.c or cp/typeck.c.  */
60       FOREACH_FUNCTION_ARGS(type, arg, args_iter)
61         {
62           HOST_WIDE_INT parm_size;
63           unsigned HOST_WIDE_INT parm_boundary_bytes;
64
65           if (! COMPLETE_TYPE_P (arg))
66             break;
67
68           parm_size = int_size_in_bytes (arg);
69           if (parm_size < 0)
70             break;
71
72           parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
73
74           /* Must round up to include padding.  This is done the same
75              way as in store_one_arg.  */
76           total += (parm_size + parm_boundary_bytes - 1)
77                    / parm_boundary_bytes * parm_boundary_bytes;
78         }
79     }
80
81   new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 10 + 1);
82   sprintf (new_str, "%c%s@" HOST_WIDE_INT_PRINT_UNSIGNED,
83            prefix, old_str, total);
84
85   return get_identifier (new_str);
86 }
87
88 /* Return string which is the function name, identified by ID, modified
89    with an _n@ prefix (where n represents the number of arguments passed in
90    registers).  If ID is NULL use the DECL_NAME as base.
91    Return NULL if no change required.  */
92
93 static tree
94 gen_regparm_prefix (tree decl, tree id, unsigned int nregs)
95 {
96   unsigned HOST_WIDE_INT total = 0;
97   const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
98   char *new_str;
99   tree type = TREE_TYPE (decl);
100
101   if (prototype_p (type))
102     {
103       tree arg;
104       function_args_iterator args_iter;
105
106       /* This attribute is ignored for variadic functions.  */ 
107       if (stdarg_p (type))
108         return NULL_TREE;
109
110       /* Quit if we hit an incomplete type.  Error is reported
111          by convert_arguments in c-typeck.c or cp/typeck.c.  */
112       FOREACH_FUNCTION_ARGS(type, arg, args_iter)
113         {
114           HOST_WIDE_INT parm_size;
115           unsigned HOST_WIDE_INT parm_boundary_bytes;
116
117           if (! COMPLETE_TYPE_P (arg))
118             break;
119
120           parm_size = int_size_in_bytes (arg);
121           if (parm_size < 0)
122             break;
123
124           parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
125
126           /* Must round up to include padding.  This is done the same
127              way as in store_one_arg.  */
128           total += (parm_size + parm_boundary_bytes - 1)
129                    / parm_boundary_bytes * parm_boundary_bytes;
130         }
131     }
132
133   if (nregs > total / UNITS_PER_WORD)
134     nregs = total / UNITS_PER_WORD;
135   gcc_assert (nregs <= 9);
136   new_str = XALLOCAVEC (char, 3 + strlen (old_str) + 1);
137   sprintf (new_str, "_%u@%s", nregs, old_str);
138
139   return get_identifier (new_str);
140 }
141
142 /* Maybe decorate and get a new identifier for the DECL of a stdcall or
143    fastcall function. The original identifier is supplied in ID. */
144
145 static tree
146 i386_nlm_maybe_mangle_decl_assembler_name (tree decl, tree id)
147 {
148   tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
149   tree new_id;
150
151   if (lookup_attribute ("stdcall", type_attributes))
152     new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
153   else if (lookup_attribute ("fastcall", type_attributes))
154     new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
155   else if ((new_id = lookup_attribute ("regparm", type_attributes)))
156     new_id = gen_regparm_prefix (decl, id,
157                   TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (new_id))));
158   else
159     new_id = NULL_TREE;
160
161   return new_id;
162 }
163
164 /* This is used as a target hook to modify the DECL_ASSEMBLER_NAME
165    in the language-independent default hook
166    langhooks.c:lhd_set_decl_assembler_name ()
167    and in cp/mangle.c:mangle_decl ().  */
168 tree
169 i386_nlm_mangle_decl_assembler_name (tree decl, tree id)
170 {
171   tree new_id = TREE_CODE (decl) == FUNCTION_DECL
172                 ? i386_nlm_maybe_mangle_decl_assembler_name (decl, id)
173                 : NULL_TREE;
174
175   return (new_id ? new_id : id);
176 }
177
178 void
179 i386_nlm_encode_section_info (tree decl, rtx rtl, int first)
180 {
181   default_encode_section_info (decl, rtl, first);
182
183   if (TREE_CODE (decl) == FUNCTION_DECL
184       /* Do not change the identifier if a verbatim asmspec
185          or if stdcall suffix already added.  */
186       && *IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) != '*'
187       && !strchr (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), '@')
188       /* FIXME:  Imported stdcall names are not modified by the Ada frontend.
189          Check and decorate the RTL name now.  */
190       && strcmp (lang_hooks.name, "GNU Ada") == 0)
191     {
192       rtx symbol = XEXP (rtl, 0);
193       tree new_id;
194       tree old_id = DECL_ASSEMBLER_NAME (decl);
195
196       gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
197
198       if ((new_id = i386_nlm_maybe_mangle_decl_assembler_name (decl, old_id)))
199         XSTR (symbol, 0) = IDENTIFIER_POINTER (new_id);
200     }
201 }
202
203 /* Strip the stdcall/fastcall/regparm pre-/suffix.  */
204
205 const char *
206 i386_nlm_strip_name_encoding (const char *str)
207 {
208   const char *name = default_strip_name_encoding (str);
209
210   if (*str != '*' && (*name == '_' || *name == '@'))
211     {
212       const char *p = strchr (name + 1, '@');
213
214       if (p)
215         {
216           ++name;
217           if (ISDIGIT (p[1]))
218             name = ggc_alloc_string (name, p - name);
219           else
220             {
221               gcc_assert (ISDIGIT (*name));
222               name++;
223               gcc_assert (name == p);
224             }
225         }
226     }
227   return name;
228 }