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