Comment PFIL_HOOKS since it should not be needed in GENERIC.
[dragonfly.git] / contrib / gcc / halfpic.c
1 /* OSF/rose half-pic support functions.
2    Copyright (C) 1992, 1997, 1998 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* The OSF/rose half-pic model assumes that the non-library code does
22    not need to have full PIC (position independent code), but rather,
23    that pointers to external references are put into the data section
24    and dereferenced as normal pointers.  References to static data does
25    not need to be PIC-ized.
26
27    Another optimization is to have the compiler know what symbols are
28    in the shared libraries, and to only lay down the pointers to
29    things which in the library proper.  */
30
31 #include "config.h"
32
33 #ifdef HALF_PIC_INIT
34
35 #include "system.h"
36 #include "tree.h"
37 #include "rtl.h"
38 #include "obstack.h"
39
40 #define obstack_chunk_alloc xmalloc
41 #define obstack_chunk_free free
42
43 extern rtx eliminate_constant_term ();
44 extern void assemble_name ();
45 extern void output_addr_const ();
46
47 int flag_half_pic               = 0;    /* Global half-pic flag.  */
48 int half_pic_number_ptrs        = 0;    /* # distinct pointers found */
49 int half_pic_number_refs        = 0;    /* # half-pic references */
50 int (*ptr_half_pic_address_p)() = half_pic_address_p;
51
52 /* Obstack to hold generated pic names.  */
53 static struct obstack half_pic_obstack;
54
55 /* List of pointers created to pic references.  */
56
57 struct all_refs {
58   struct all_refs *hash_next;   /* next name in hash chain */
59   struct all_refs *next;        /* next name created */
60   int              external_p;  /* name is an external reference */
61   int              pointer_p;   /* pointer created.  */
62   char            *ref_name;    /* reference name to ptr to real_name */
63   int              ref_len;     /* reference name length */
64   char            *real_name;   /* real function/data name */
65   int              real_len;    /* strlen (real_name) */
66 };
67
68 static struct all_refs *half_pic_names;
69
70 static char *half_pic_prefix;
71 static int   half_pic_prefix_len;
72
73 \f
74 /* Return the hash bucket of a name or NULL.  The hash chain is
75    organized as a self reorganizing circularly linked chain.  It is
76    assumed that any name passed to use will never be reallocated.  For
77    names in SYMBOL_REF's this is true, because the names are allocated
78    on the permanent obstack.  */
79
80 #ifndef MAX_HASH_TABLE
81 #define MAX_HASH_TABLE 1009
82 #endif
83
84 #define HASHBITS 30
85
86 static struct all_refs *
87 half_pic_hash (name, len, create_p)
88      char *name;                /* name to hash */
89      int len;                   /* length of the name (or 0 to call strlen) */
90      int create_p;              /* != 0 to create new hash bucket if new */
91 {
92   static struct all_refs *hash_table[MAX_HASH_TABLE];
93   static struct all_refs  zero_all_refs;
94
95   unsigned char *uname;
96   int hash;
97   int i;
98   int ch;
99   struct all_refs *first;
100   struct all_refs *ptr;
101
102   if (len == 0)
103     len = strlen (name);
104
105   /* Compute hash code */
106   uname = (unsigned char *)name;
107   ch = uname[0];
108   hash = len * 613 + ch;
109   for (i = 1; i < len; i += 2)
110     hash = (hash * 613) + uname[i];
111
112   hash &= (1 << HASHBITS) - 1;
113   hash %= MAX_HASH_TABLE;
114
115   /* See if the name is in the hash table.  */
116   ptr = first = hash_table[hash];
117   if (ptr)
118     {
119       do
120         {
121           if (len == ptr->real_len
122               && ch == *(ptr->real_name)
123               && !strcmp (name, ptr->real_name))
124             {
125               hash_table[hash] = ptr;
126               return ptr;
127             }
128
129           ptr = ptr->hash_next;
130         }
131       while (ptr != first);
132     }
133
134   /* name not in hash table.  */
135   if (!create_p)
136     return (struct all_refs *) 0;
137
138   ptr = (struct all_refs *) obstack_alloc (&half_pic_obstack, sizeof (struct all_refs));
139   *ptr = zero_all_refs;
140
141   ptr->real_name = name;
142   ptr->real_len  = len;
143
144   /* Update circular links.  */
145   if (first == (struct all_refs *) 0)
146     ptr->hash_next = ptr;
147
148   else
149     {
150       ptr->hash_next = first->hash_next;
151       first->hash_next = ptr;
152     }
153
154   hash_table[hash] = ptr;
155   return ptr;
156 }
157
158 \f
159 /* Do any half-pic initializations.  */
160
161 void
162 half_pic_init ()
163 {
164   flag_half_pic = TRUE;
165   half_pic_prefix = HALF_PIC_PREFIX;
166   half_pic_prefix_len = strlen (half_pic_prefix);
167   obstack_init (&half_pic_obstack);
168 }
169
170 \f
171 /* Write out all pointers to pic references.  */
172
173 void
174 half_pic_finish (stream)
175      FILE *stream;
176 {
177   struct all_refs *p = half_pic_names;
178
179   if (!p)
180     return;
181
182   data_section ();
183   for (; p != 0; p = p->next)
184     {
185       /* Emit the pointer if used.  */
186       if (p->pointer_p)
187         {
188           ASM_OUTPUT_LABEL (stream, p->ref_name);
189           ASM_OUTPUT_INT (stream, gen_rtx_SYMBOL_REF (Pmode, p->real_name));
190         }
191     }
192 }
193
194 \f
195 /* Encode in a declaration whether or not it is half-pic.  */
196
197 void
198 half_pic_encode (decl)
199      tree decl;
200 {
201   enum tree_code code = TREE_CODE (decl);
202   tree asm_name;
203   struct all_refs *ptr;
204
205   if (!flag_half_pic)
206     return;
207
208   if (code != VAR_DECL && code != FUNCTION_DECL)
209     return;
210
211   asm_name = DECL_ASSEMBLER_NAME (decl);
212
213   if (!asm_name)
214     return;
215
216 #ifdef HALF_PIC_DEBUG
217   if (HALF_PIC_DEBUG)
218     {
219       fprintf (stderr, "\n========== Half_pic_encode %.*s\n",
220                IDENTIFIER_LENGTH (asm_name),
221                IDENTIFIER_POINTER (asm_name));
222       debug_tree (decl);
223     }
224 #endif
225
226   /* If this is not an external reference, it can't be half-pic.  */
227   if (!DECL_EXTERNAL (decl) && (code != VAR_DECL || !TREE_PUBLIC (decl)))
228     return;
229
230   ptr = half_pic_hash (IDENTIFIER_POINTER (asm_name),
231                        IDENTIFIER_LENGTH (asm_name),
232                        TRUE);
233
234   ptr->external_p = TRUE;
235
236 #ifdef HALF_PIC_DEBUG
237   if (HALF_PIC_DEBUG)
238     fprintf (stderr, "\n%.*s is half-pic\n",
239              IDENTIFIER_LENGTH (asm_name),
240              IDENTIFIER_POINTER (asm_name));
241 #endif
242 }
243
244 \f
245 /* Mark that an object is now local, and no longer needs half-pic.  */
246
247 void
248 half_pic_declare (name)
249      char *name;
250 {
251   struct all_refs *ptr;
252
253   if (!flag_half_pic)
254     return;
255
256   ptr = half_pic_hash (name, 0, FALSE);
257   if (!ptr)
258     return;
259
260   ptr->external_p = FALSE;
261
262 #ifdef HALF_PIC_DEBUG
263   if (HALF_PIC_DEBUG)
264     fprintf (stderr, "\n========== Half_pic_declare %s\n", name);
265 #endif
266 }
267
268 \f
269 /* Mark that an object is explicitly external.  */
270
271 void
272 half_pic_external (name)
273      char *name;
274 {
275   struct all_refs *ptr;
276
277   if (!flag_half_pic)
278     return;
279
280   ptr = half_pic_hash (name, 0, TRUE);
281   if (!ptr)
282     return;
283
284   ptr->external_p = TRUE;
285
286 #ifdef HALF_PIC_DEBUG
287   if (HALF_PIC_DEBUG)
288     fprintf (stderr, "\n========== Half_pic_external %s\n", name);
289 #endif
290 }
291
292 \f
293 /* Return whether an address is half-pic.  */
294
295 int
296 half_pic_address_p (addr)
297      rtx addr;
298 {
299   char *name;
300   int len;
301   struct all_refs *ptr;
302
303   if (!flag_half_pic)
304     return FALSE;
305
306   switch (GET_CODE (addr))
307     {
308     default:
309       break;
310
311     case CONST:
312       {
313         rtx offset = const0_rtx;
314         addr = eliminate_constant_term (XEXP (addr, 0), &offset);
315         if (GET_CODE (addr) != SYMBOL_REF)
316           return FALSE;
317       }
318       /* fall through */
319
320     case SYMBOL_REF:
321       name = XSTR (addr, 0);
322
323 #ifdef HALF_PIC_DEBUG
324       if (HALF_PIC_DEBUG)
325         fprintf (stderr, "\n========== Half_pic_address_p %s\n", name);
326 #endif
327
328       /* If this is a label, it will have a '*' in front of it.  */
329       if (name[0] == '*')
330         return FALSE;
331
332       /* If this is a reference to the actual half-pic pointer, it
333          is obviously not half-pic.  */
334
335       len = strlen (name);
336       if (len > half_pic_prefix_len
337           && half_pic_prefix[0] == name[0]
338           && !strncmp (name, half_pic_prefix, half_pic_prefix_len))
339         return FALSE;
340
341       ptr = half_pic_hash (name, len, FALSE);
342       if (ptr == (struct all_refs *) 0)
343         return FALSE;
344
345       if (ptr->external_p)
346         {
347 #ifdef HALF_PIC_DEBUG
348           if (HALF_PIC_DEBUG)
349             fprintf (stderr, "%s is half-pic\n", name);
350 #endif
351           return TRUE;
352         }
353     }
354
355   return FALSE;
356 }
357
358 \f
359 /* Return the name of the pointer to the PIC function, allocating
360    it if need be.  */
361
362 struct rtx_def *
363 half_pic_ptr (operand)
364      rtx operand;
365 {
366   char *name;
367   struct all_refs *p;
368   int len;
369
370   if (GET_CODE (operand) != SYMBOL_REF)
371     return operand;
372
373   name = XSTR (operand, 0);
374   len = strlen (name);
375   p = half_pic_hash (name, len, FALSE);
376   if (p == (struct all_refs *) 0 || !p->external_p)
377     return operand;
378
379   if (!p->pointer_p)
380     {                           /* first time, create pointer */
381       obstack_grow (&half_pic_obstack, half_pic_prefix, half_pic_prefix_len);
382       obstack_grow (&half_pic_obstack, name, len+1);
383
384       p->next      = half_pic_names;
385       p->ref_name  = (char *) obstack_finish (&half_pic_obstack);
386       p->ref_len   = len + half_pic_prefix_len;
387       p->pointer_p = TRUE;
388
389       half_pic_names = p;
390       half_pic_number_ptrs++;
391     }
392
393   half_pic_number_refs++;
394   return gen_rtx_SYMBOL_REF (Pmode, p->ref_name);
395 }
396
397 #endif /* HALF_PIC_INIT */