0
|
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"
|
36
|
33 #include "langhooks.h"
|
0
|
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
|
36
|
183 if (TREE_CODE (decl) == FUNCTION_DECL
|
0
|
184 /* Do not change the identifier if a verbatim asmspec
|
|
185 or if stdcall suffix already added. */
|
|
186 && *IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) != '*'
|
36
|
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)
|
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)))
|
36
|
199 XSTR (symbol, 0) = IDENTIFIER_POINTER (new_id);
|
0
|
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 }
|