1/* OSF/rose half-pic support functions.
2   Copyright (C) 1992, 1997, 1998 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING.  If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, 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
43extern rtx eliminate_constant_term ();
44extern void assemble_name ();
45extern void output_addr_const ();
46
47int flag_half_pic		= 0;	/* Global half-pic flag.  */
48int half_pic_number_ptrs	= 0;	/* # distinct pointers found */
49int half_pic_number_refs	= 0;	/* # half-pic references */
50int (*ptr_half_pic_address_p)() = half_pic_address_p;
51
52/* Obstack to hold generated pic names.  */
53static struct obstack half_pic_obstack;
54
55/* List of pointers created to pic references.  */
56
57struct 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
68static struct all_refs *half_pic_names;
69
70static char *half_pic_prefix;
71static int   half_pic_prefix_len;
72
73
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
86static struct all_refs *
87half_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
159/* Do any half-pic initializations.  */
160
161void
162half_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
171/* Write out all pointers to pic references.  */
172
173void
174half_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
195/* Encode in a declaration whether or not it is half-pic.  */
196
197void
198half_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
245/* Mark that an object is now local, and no longer needs half-pic.  */
246
247void
248half_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
269/* Mark that an object is explicitly external.  */
270
271void
272half_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
293/* Return whether an address is half-pic.  */
294
295int
296half_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
359/* Return the name of the pointer to the PIC function, allocating
360   it if need be.  */
361
362struct rtx_def *
363half_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 */
398