OSDN Git Service

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