OSDN Git Service

* rtl.h (mem_attrs): Rename decl to expr; adjust all users.
[pf3gnuchains/gcc-fork.git] / gcc / halfpic.c
1 /* OSF/rose half-pic support functions.
2    Copyright (C) 1992, 1997, 1998, 1999 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING.  If not, write to the Free
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 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 "expr.h"
39 #include "output.h"
40 #include "obstack.h"
41 #include "halfpic.h"
42
43 #define obstack_chunk_alloc xmalloc
44 #define obstack_chunk_free free
45
46 int flag_half_pic               = 0;    /* Global half-pic flag.  */
47 int half_pic_number_ptrs        = 0;    /* # distinct pointers found */
48 int half_pic_number_refs        = 0;    /* # half-pic references */
49 int (*ptr_half_pic_address_p) PARAMS ((rtx)) = half_pic_address_p;
50
51 /* Obstack to hold generated pic names.  */
52 static struct obstack half_pic_obstack;
53
54 /* List of pointers created to pic references.  */
55
56 struct all_refs {
57   struct all_refs *hash_next;   /* next name in hash chain */
58   struct all_refs *next;        /* next name created */
59   int              external_p;  /* name is an external reference */
60   int              pointer_p;   /* pointer created.  */
61   const char      *ref_name;    /* reference name to ptr to real_name */
62   int              ref_len;     /* reference name length */
63   const char      *real_name;   /* real function/data name */
64   int              real_len;    /* strlen (real_name) */
65 };
66
67 static struct all_refs *half_pic_names;
68
69 static const char *half_pic_prefix;
70 static int   half_pic_prefix_len;
71
72 \f
73 /* Return the hash bucket of a name or NULL.  The hash chain is
74    organized as a self reorganizing circularly linked chain.  It is
75    assumed that any name passed to use will never be reallocated.  For
76    names in SYMBOL_REF's this is true, because the names are allocated
77    on the permanent obstack.  */
78
79 #ifndef MAX_HASH_TABLE
80 #define MAX_HASH_TABLE 1009
81 #endif
82
83 #define HASHBITS 30
84
85 static struct all_refs *half_pic_hash PARAMS ((const char *, int, int));
86
87 static struct all_refs *
88 half_pic_hash (name, len, create_p)
89      const 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   const 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 = (const 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   asm_name = DECL_ASSEMBLER_NAME (decl);
213
214   if (!asm_name)
215     return;
216
217 #ifdef HALF_PIC_DEBUG
218   if (HALF_PIC_DEBUG)
219     {
220       fprintf (stderr, "\n========== Half_pic_encode %.*s\n",
221                IDENTIFIER_LENGTH (asm_name),
222                IDENTIFIER_POINTER (asm_name));
223       debug_tree (decl);
224     }
225 #endif
226
227   /* If this is not an external reference, it can't be half-pic.  */
228   if (!DECL_EXTERNAL (decl) && (code != VAR_DECL || !TREE_PUBLIC (decl)))
229     return;
230
231   ptr = half_pic_hash (IDENTIFIER_POINTER (asm_name),
232                        IDENTIFIER_LENGTH (asm_name),
233                        TRUE);
234
235   ptr->external_p = TRUE;
236
237 #ifdef HALF_PIC_DEBUG
238   if (HALF_PIC_DEBUG)
239     fprintf (stderr, "\n%.*s is half-pic\n",
240              IDENTIFIER_LENGTH (asm_name),
241              IDENTIFIER_POINTER (asm_name));
242 #endif
243 }
244
245 \f
246 /* Mark that an object is now local, and no longer needs half-pic.  */
247
248 void
249 half_pic_declare (name)
250      const char *name;
251 {
252   struct all_refs *ptr;
253
254   if (!flag_half_pic)
255     return;
256
257   ptr = half_pic_hash (name, 0, FALSE);
258   if (!ptr)
259     return;
260
261   ptr->external_p = FALSE;
262
263 #ifdef HALF_PIC_DEBUG
264   if (HALF_PIC_DEBUG)
265     fprintf (stderr, "\n========== Half_pic_declare %s\n", name);
266 #endif
267 }
268
269 \f
270 /* Mark that an object is explicitly external.  */
271
272 void
273 half_pic_external (name)
274      const char *name;
275 {
276   struct all_refs *ptr;
277
278   if (!flag_half_pic)
279     return;
280
281   ptr = half_pic_hash (name, 0, TRUE);
282   if (!ptr)
283     return;
284
285   ptr->external_p = TRUE;
286
287 #ifdef HALF_PIC_DEBUG
288   if (HALF_PIC_DEBUG)
289     fprintf (stderr, "\n========== Half_pic_external %s\n", name);
290 #endif
291 }
292
293 \f
294 /* Return whether an address is half-pic.  */
295
296 int
297 half_pic_address_p (addr)
298      rtx addr;
299 {
300   const char *name;
301   int len;
302   struct all_refs *ptr;
303
304   if (!flag_half_pic)
305     return FALSE;
306
307   switch (GET_CODE (addr))
308     {
309     default:
310       break;
311
312     case CONST:
313       {
314         rtx offset = const0_rtx;
315         addr = eliminate_constant_term (XEXP (addr, 0), &offset);
316         if (GET_CODE (addr) != SYMBOL_REF)
317           return FALSE;
318       }
319       /* fall through */
320
321     case SYMBOL_REF:
322       name = XSTR (addr, 0);
323
324 #ifdef HALF_PIC_DEBUG
325       if (HALF_PIC_DEBUG)
326         fprintf (stderr, "\n========== Half_pic_address_p %s\n", name);
327 #endif
328
329       /* If this is a label, it will have a '*' in front of it.  */
330       if (name[0] == '*')
331         return FALSE;
332
333       /* If this is a reference to the actual half-pic pointer, it
334          is obviously not half-pic.  */
335
336       len = strlen (name);
337       if (len > half_pic_prefix_len
338           && half_pic_prefix[0] == name[0]
339           && !strncmp (name, half_pic_prefix, half_pic_prefix_len))
340         return FALSE;
341
342       ptr = half_pic_hash (name, len, FALSE);
343       if (ptr == (struct all_refs *) 0)
344         return FALSE;
345
346       if (ptr->external_p)
347         {
348 #ifdef HALF_PIC_DEBUG
349           if (HALF_PIC_DEBUG)
350             fprintf (stderr, "%s is half-pic\n", name);
351 #endif
352           return TRUE;
353         }
354     }
355
356   return FALSE;
357 }
358
359 \f
360 /* Return the name of the pointer to the PIC function, allocating
361    it if need be.  */
362
363 struct rtx_def *
364 half_pic_ptr (operand)
365      rtx operand;
366 {
367   const char *name;
368   struct all_refs *p;
369   int len;
370
371   if (GET_CODE (operand) != SYMBOL_REF)
372     return operand;
373
374   name = XSTR (operand, 0);
375   len = strlen (name);
376   p = half_pic_hash (name, len, FALSE);
377   if (p == (struct all_refs *) 0 || !p->external_p)
378     return operand;
379
380   if (!p->pointer_p)
381     {                           /* first time, create pointer */
382       obstack_grow (&half_pic_obstack, half_pic_prefix, half_pic_prefix_len);
383       obstack_grow (&half_pic_obstack, name, len+1);
384
385       p->next      = half_pic_names;
386       p->ref_name  = (char *) obstack_finish (&half_pic_obstack);
387       p->ref_len   = len + half_pic_prefix_len;
388       p->pointer_p = TRUE;
389
390       half_pic_names = p;
391       half_pic_number_ptrs++;
392     }
393
394   half_pic_number_refs++;
395   return gen_rtx_SYMBOL_REF (Pmode, p->ref_name);
396 }
397
398 #endif /* HALF_PIC_INIT */