OSDN Git Service

gcc/
[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 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 2, 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 COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "output.h"
30 #include "tree.h"
31 #include "flags.h"
32 #include "tm_p.h"
33 #include "toplev.h"
34 #include "ggc.h"
35
36
37 /* Return string which is the former assembler name modified with an 
38    underscore prefix and a suffix consisting of an atsign (@) followed
39    by the number of bytes of arguments */
40
41 static tree
42 gen_stdcall_or_fastcall_decoration (tree decl, char prefix)
43 {
44   unsigned total = 0;
45   /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
46      of DECL_ASSEMBLER_NAME.  */
47   const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
48   char *newsym;
49   tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
50
51   if (formal_type != NULL_TREE)
52     {
53       /* These attributes are ignored for variadic functions in
54          i386.c:ix86_return_pops_args. For compatibility with MS
55          compiler do not add @0 suffix here.  */ 
56       if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
57         return NULL_TREE;
58
59       /* Quit if we hit an incomplete type.  Error is reported
60          by convert_arguments in c-typeck.c or cp/typeck.c.  */
61       while (TREE_VALUE (formal_type) != void_type_node
62              && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))     
63         {
64           unsigned parm_size
65             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
66
67           /* Must round up to include padding.  This is done the same
68              way as in store_one_arg.  */
69           parm_size = ((parm_size + PARM_BOUNDARY - 1)
70                        / PARM_BOUNDARY * PARM_BOUNDARY);
71           total += parm_size;
72           formal_type = TREE_CHAIN (formal_type);
73         }
74     }
75
76   newsym = alloca (1 + strlen (asmname) + 1 + 10 + 1);
77   return get_identifier_with_length (newsym,
78                                      sprintf (newsym,
79                                               "%c%s@%u",
80                                               prefix,
81                                               asmname,
82                                               total / BITS_PER_UNIT));
83 }
84
85 /* Return string which is the former assembler name modified with an 
86    _n@ prefix where n represents the number of arguments passed in
87    registers */
88
89 static tree
90 gen_regparm_prefix (tree decl, unsigned nregs)
91 {
92   unsigned total = 0;
93   /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
94      of DECL_ASSEMBLER_NAME.  */
95   const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
96   char *newsym;
97   tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
98
99   if (formal_type != NULL_TREE)
100     {
101       /* This attribute is ignored for variadic functions.  */ 
102       if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
103         return NULL_TREE;
104
105       /* Quit if we hit an incomplete type.  Error is reported
106          by convert_arguments in c-typeck.c or cp/typeck.c.  */
107       while (TREE_VALUE (formal_type) != void_type_node
108              && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))     
109         {
110           unsigned parm_size
111             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
112
113           /* Must round up to include padding.  This is done the same
114              way as in store_one_arg.  */
115           parm_size = ((parm_size + PARM_BOUNDARY - 1)
116                        / PARM_BOUNDARY * PARM_BOUNDARY);
117           total += parm_size;
118           formal_type = TREE_CHAIN (formal_type);
119         }
120     }
121
122   if (nregs > total / BITS_PER_WORD)
123     nregs = total / BITS_PER_WORD;
124   gcc_assert (nregs <= 9);
125   newsym = alloca (3 + strlen (asmname) + 1);
126   return get_identifier_with_length (newsym,
127                                      sprintf (newsym,
128                                               "_%u@%s",
129                                               nregs,
130                                               asmname));
131 }
132
133 void
134 i386_nlm_encode_section_info (tree decl, rtx rtl, int first)
135 {
136   default_encode_section_info (decl, rtl, first);
137
138   if (first
139       && TREE_CODE (decl) == FUNCTION_DECL
140       && *IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) != '*'
141       && !strchr (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), '@'))
142     {
143       tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
144       tree newid;
145
146       if (lookup_attribute ("stdcall", type_attributes))
147         newid = gen_stdcall_or_fastcall_decoration (decl, '_');
148       else if (lookup_attribute ("fastcall", type_attributes))
149         newid = gen_stdcall_or_fastcall_decoration (decl, FASTCALL_PREFIX);
150       else if ((newid = lookup_attribute ("regparm", type_attributes)) != NULL_TREE)
151         newid = gen_regparm_prefix (decl,
152                       TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (newid))));
153       if (newid != NULL_TREE)   
154         {
155           rtx rtlname = XEXP (rtl, 0);
156
157           if (GET_CODE (rtlname) == MEM)
158             rtlname = XEXP (rtlname, 0);
159           XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
160           /* These attributes must be present on first declaration,
161              change_decl_assembler_name will warn if they are added
162              later and the decl has been referenced, but duplicate_decls
163              should catch the mismatch before this is called.  */ 
164           change_decl_assembler_name (decl, newid);
165         }
166     }
167 }
168
169 /* Strip the stdcall/fastcall/regparm pre-/suffix.  */
170
171 const char *
172 i386_nlm_strip_name_encoding (const char *str)
173 {
174   const char *name = default_strip_name_encoding (str);
175
176   if (*str != '*' && (*name == '_' || *name == '@'))
177     {
178       const char *p = strchr (name + 1, '@');
179
180       if (p)
181         {
182           ++name;
183           if (ISDIGIT (p[1]))
184             name = ggc_alloc_string (name, p - name);
185           else
186             {
187               gcc_assert (ISDIGIT (*name));
188               name++;
189               gcc_assert (name == p);
190             }
191         }
192     }
193   return name;
194 }