darwin.c revision 90075
1/* Functions for generic Darwin as target machine for GNU C compiler.
2   Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001
3   Free Software Foundation, Inc.
4   Contributed by Apple Computer Inc.
5
6This file is part of GNU CC.
7
8GNU CC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13GNU CC is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU CC; see the file COPYING.  If not, write to
20the Free Software Foundation, 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA.  */
22
23#include "config.h"
24#include "system.h"
25#include "rtl.h"
26#include "regs.h"
27#include "hard-reg-set.h"
28#include "real.h"
29#include "insn-config.h"
30#include "conditions.h"
31#include "insn-flags.h"
32#include "output.h"
33#include "insn-attr.h"
34#include "flags.h"
35#include "tree.h"
36#include "expr.h"
37#include "reload.h"
38#include "function.h"
39#include "ggc.h"
40#include "langhooks.h"
41
42#include "darwin-protos.h"
43
44extern void machopic_output_stub PARAMS ((FILE *, const char *, const char *));
45
46static int machopic_data_defined_p PARAMS ((const char *));
47static int func_name_maybe_scoped PARAMS ((const char *));
48static void update_non_lazy_ptrs PARAMS ((const char *));
49static void update_stubs PARAMS ((const char *));
50
51int
52name_needs_quotes (name)
53     const char *name;
54{
55  int c;
56  while ((c = *name++) != '\0')
57    if (! ISIDNUM (c))
58      return 1;
59  return 0;
60}
61
62/*
63 * flag_pic = 1 ... generate only indirections
64 * flag_pic = 2 ... generate indirections and pure code
65 */
66
67/* This module assumes that (const (symbol_ref "foo")) is a legal pic
68   reference, which will not be changed.  */
69
70static tree machopic_defined_list;
71
72enum machopic_addr_class
73machopic_classify_ident (ident)
74     tree ident;
75{
76  const char *name = IDENTIFIER_POINTER (ident);
77  int lprefix = (((name[0] == '*' || name[0] == '&')
78		  && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
79		 || (   name[0] == '_'
80		     && name[1] == 'O'
81		     && name[2] == 'B'
82		     && name[3] == 'J'
83		     && name[4] == 'C'
84		     && name[5] == '_'));
85  tree temp;
86
87  if (name[0] != '!')
88    {
89      /* Here if no special encoding to be found.  */
90      if (lprefix)
91	{
92	  const char *name = IDENTIFIER_POINTER (ident);
93	  int len = strlen (name);
94
95	  if ((len > 5 && !strcmp (name + len - 5, "$stub"))
96	      || (len > 6 && !strcmp (name + len - 6, "$stub\"")))
97	    return MACHOPIC_DEFINED_FUNCTION;
98	  return MACHOPIC_DEFINED_DATA;
99	}
100
101      for (temp = machopic_defined_list;
102	   temp != NULL_TREE;
103	   temp = TREE_CHAIN (temp))
104	{
105	  if (ident == TREE_VALUE (temp))
106	    return MACHOPIC_DEFINED_DATA;
107	}
108
109      if (TREE_ASM_WRITTEN (ident))
110	return MACHOPIC_DEFINED_DATA;
111
112      return MACHOPIC_UNDEFINED;
113    }
114
115  else if (name[1] == 'D')
116    return MACHOPIC_DEFINED_DATA;
117
118  else if (name[1] == 'T')
119    return MACHOPIC_DEFINED_FUNCTION;
120
121  /* It is possible that someone is holding a "stale" name, which has
122     since been defined.  See if there is a "defined" name (i.e,
123     different from NAME only in having a '!D_' or a '!T_' instead of
124     a '!d_' or '!t_' prefix) in the identifier hash tables.  If so, say
125     that this identifier is defined.  */
126  else if (name[1] == 'd' || name[1] == 't')
127    {
128      char *new_name;
129      new_name = (char *)alloca (strlen (name) + 1);
130      strcpy (new_name, name);
131      new_name[1] = (name[1] == 'd') ? 'D' : 'T';
132      if (maybe_get_identifier (new_name) != NULL)
133	return  (name[1] == 'd') ? MACHOPIC_DEFINED_DATA
134				 : MACHOPIC_DEFINED_FUNCTION;
135    }
136
137  for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp))
138    {
139      if (ident == TREE_VALUE (temp))
140	{
141	  if (name[1] == 'T')
142	    return MACHOPIC_DEFINED_FUNCTION;
143	  else
144	    return MACHOPIC_DEFINED_DATA;
145	}
146    }
147
148  if (name[1] == 't' || name[1] == 'T')
149    {
150      if (lprefix)
151	return MACHOPIC_DEFINED_FUNCTION;
152      else
153	return MACHOPIC_UNDEFINED_FUNCTION;
154    }
155  else
156    {
157      if (lprefix)
158	return MACHOPIC_DEFINED_DATA;
159      else
160	return MACHOPIC_UNDEFINED_DATA;
161    }
162}
163
164
165enum machopic_addr_class
166machopic_classify_name (name)
167     const char *name;
168{
169  return machopic_classify_ident (get_identifier (name));
170}
171
172int
173machopic_ident_defined_p (ident)
174     tree ident;
175{
176  switch (machopic_classify_ident (ident))
177    {
178    case MACHOPIC_UNDEFINED:
179    case MACHOPIC_UNDEFINED_DATA:
180    case MACHOPIC_UNDEFINED_FUNCTION:
181      return 0;
182    default:
183      return 1;
184    }
185}
186
187static int
188machopic_data_defined_p (name)
189     const char *name;
190{
191  switch (machopic_classify_ident (get_identifier (name)))
192    {
193    case MACHOPIC_DEFINED_DATA:
194      return 1;
195    default:
196      return 0;
197    }
198}
199
200int
201machopic_name_defined_p (name)
202     const char *name;
203{
204  return machopic_ident_defined_p (get_identifier (name));
205}
206
207void
208machopic_define_ident (ident)
209     tree ident;
210{
211  if (!machopic_ident_defined_p (ident))
212    machopic_defined_list =
213      tree_cons (NULL_TREE, ident, machopic_defined_list);
214}
215
216void
217machopic_define_name (name)
218     const char *name;
219{
220  machopic_define_ident (get_identifier (name));
221}
222
223/* This is a static to make inline functions work.  The rtx
224   representing the PIC base symbol always points to here. */
225
226static char function_base[32];
227
228static int current_pic_label_num;
229
230char *
231machopic_function_base_name ()
232{
233  static const char *name = NULL;
234  static const char *current_name;
235
236  current_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
237
238  if (name != current_name)
239    {
240      current_function_uses_pic_offset_table = 1;
241
242      /* Save mucho space and time.  Some of the C++ mangled names are over
243	 700 characters long!  Note that we produce a label containing a '-'
244	 if the function we're compiling is an Objective-C method, as evinced
245	 by the incredibly scientific test below.  This is because code in
246	 rs6000.c makes the same ugly test when loading the PIC reg.  */
247
248      ++current_pic_label_num;
249      if (*current_name == '+' || *current_name == '-')
250	sprintf (function_base, "*\"L-%d$pb\"", current_pic_label_num);
251      else
252	sprintf (function_base, "*L%d$pb", current_pic_label_num);
253
254      name = current_name;
255    }
256
257  return function_base;
258}
259
260static tree machopic_non_lazy_pointers = NULL;
261
262/* Return a non-lazy pointer name corresponding to the given name,
263   either by finding it in our list of pointer names, or by generating
264   a new one.  */
265
266char *
267machopic_non_lazy_ptr_name (name)
268     const char *name;
269{
270  char *temp_name;
271  tree temp, ident = get_identifier (name);
272
273  for (temp = machopic_non_lazy_pointers;
274       temp != NULL_TREE;
275       temp = TREE_CHAIN (temp))
276    {
277      if (ident == TREE_VALUE (temp))
278	return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
279    }
280
281  STRIP_NAME_ENCODING (name, name);
282
283  /* Try again, but comparing names this time.  */
284  for (temp = machopic_non_lazy_pointers;
285       temp != NULL_TREE;
286       temp = TREE_CHAIN (temp))
287    {
288      if (TREE_VALUE (temp))
289	{
290	  temp_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
291	  STRIP_NAME_ENCODING (temp_name, temp_name);
292	  if (strcmp (name, temp_name) == 0)
293	    return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
294	}
295    }
296
297  {
298    char *buffer;
299    tree ptr_name;
300
301    buffer = alloca (strlen (name) + 20);
302
303    strcpy (buffer, "&L");
304    if (name[0] == '*')
305      strcat (buffer, name+1);
306    else
307      {
308	strcat (buffer, "_");
309	strcat (buffer, name);
310      }
311
312    strcat (buffer, "$non_lazy_ptr");
313    ptr_name = get_identifier (buffer);
314
315    machopic_non_lazy_pointers
316      = tree_cons (ptr_name, ident, machopic_non_lazy_pointers);
317
318    TREE_USED (machopic_non_lazy_pointers) = 0;
319
320    return IDENTIFIER_POINTER (ptr_name);
321  }
322}
323
324static tree machopic_stubs = 0;
325
326/* Make sure the GC knows about our homemade lists.  */
327
328void
329machopic_add_gc_roots ()
330{
331  ggc_add_tree_root (&machopic_defined_list, 1);
332  ggc_add_tree_root (&machopic_non_lazy_pointers, 1);
333  ggc_add_tree_root (&machopic_stubs, 1);
334}
335
336/* Return the name of the stub corresponding to the given name,
337   generating a new stub name if necessary.  */
338
339char *
340machopic_stub_name (name)
341     const char *name;
342{
343  tree temp, ident = get_identifier (name);
344  const char *tname;
345
346  for (temp = machopic_stubs;
347       temp != NULL_TREE;
348       temp = TREE_CHAIN (temp))
349    {
350      if (ident == TREE_VALUE (temp))
351	return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
352      tname = IDENTIFIER_POINTER (TREE_VALUE (temp));
353      if (strcmp (name, tname) == 0)
354	return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
355      /* A library call name might not be section-encoded yet, so try
356	 it against a stripped name.  */
357      if (name[0] != '!'
358	  && tname[0] == '!'
359	  && strcmp (name, tname + 4) == 0)
360	return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
361    }
362
363  STRIP_NAME_ENCODING (name, name);
364
365  {
366    char *buffer;
367    tree ptr_name;
368    int needs_quotes = name_needs_quotes (name);
369
370    buffer = alloca (strlen (name) + 20);
371
372    if (needs_quotes)
373      strcpy (buffer, "&\"L");
374    else
375      strcpy (buffer, "&L");
376    if (name[0] == '*')
377      {
378	strcat (buffer, name+1);
379      }
380    else
381      {
382	strcat (buffer, "_");
383	strcat (buffer, name);
384      }
385
386    if (needs_quotes)
387      strcat (buffer, "$stub\"");
388    else
389      strcat (buffer, "$stub");
390    ptr_name = get_identifier (buffer);
391
392    machopic_stubs = tree_cons (ptr_name, ident, machopic_stubs);
393    TREE_USED (machopic_stubs) = 0;
394
395    return IDENTIFIER_POINTER (ptr_name);
396  }
397}
398
399void
400machopic_validate_stub_or_non_lazy_ptr (name, validate_stub)
401     const char *name;
402     int validate_stub;
403{
404  char *real_name;
405  tree temp, ident = get_identifier (name), id2;
406
407    for (temp = (validate_stub ? machopic_stubs : machopic_non_lazy_pointers);
408         temp != NULL_TREE;
409         temp = TREE_CHAIN (temp))
410      if (ident == TREE_PURPOSE (temp))
411	{
412	  /* Mark both the stub or non-lazy pointer as well as the
413	     original symbol as being referenced.  */
414          TREE_USED (temp) = 1;
415	  if (TREE_CODE (TREE_VALUE (temp)) == IDENTIFIER_NODE)
416	    TREE_SYMBOL_REFERENCED (TREE_VALUE (temp)) = 1;
417	  STRIP_NAME_ENCODING (real_name, IDENTIFIER_POINTER (TREE_VALUE (temp)));
418	  id2 = maybe_get_identifier (real_name);
419	  if (id2)
420	    TREE_SYMBOL_REFERENCED (id2) = 1;
421	}
422}
423
424/* Transform ORIG, which may be any data source, to the corresponding
425   source using indirections.  */
426
427rtx
428machopic_indirect_data_reference (orig, reg)
429     rtx orig, reg;
430{
431  rtx ptr_ref = orig;
432
433  if (! MACHOPIC_INDIRECT)
434    return orig;
435
436  if (GET_CODE (orig) == SYMBOL_REF)
437    {
438      const char *name = XSTR (orig, 0);
439
440      if (machopic_data_defined_p (name))
441	{
442	  rtx pic_base = gen_rtx (SYMBOL_REF, Pmode,
443				  machopic_function_base_name ());
444	  rtx offset = gen_rtx (CONST, Pmode,
445				gen_rtx (MINUS, Pmode, orig, pic_base));
446
447#if defined (TARGET_TOC) /* i.e., PowerPC */
448	  rtx hi_sum_reg = reg;
449
450	  if (reg == NULL)
451	    abort ();
452
453	  emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
454			      gen_rtx (PLUS, Pmode, pic_offset_table_rtx,
455				       gen_rtx (HIGH, Pmode, offset))));
456	  emit_insn (gen_rtx (SET, Pmode, reg,
457			      gen_rtx (LO_SUM, Pmode, hi_sum_reg, offset)));
458
459	  orig = reg;
460#else
461#if defined (HAVE_lo_sum)
462	  if (reg == 0) abort ();
463
464	  emit_insn (gen_rtx (SET, VOIDmode, reg,
465			      gen_rtx (HIGH, Pmode, offset)));
466	  emit_insn (gen_rtx (SET, VOIDmode, reg,
467			      gen_rtx (LO_SUM, Pmode, reg, offset)));
468	  emit_insn (gen_rtx (USE, VOIDmode,
469			      gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
470
471	  orig = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, reg);
472#endif
473#endif
474	  return orig;
475	}
476
477      ptr_ref = gen_rtx (SYMBOL_REF, Pmode,
478                         machopic_non_lazy_ptr_name (name));
479
480      ptr_ref = gen_rtx_MEM (Pmode, ptr_ref);
481      RTX_UNCHANGING_P (ptr_ref) = 1;
482
483      return ptr_ref;
484    }
485  else if (GET_CODE (orig) == CONST)
486    {
487      rtx base, result;
488
489      /* legitimize both operands of the PLUS */
490      if (GET_CODE (XEXP (orig, 0)) == PLUS)
491	{
492	  base = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 0),
493						   reg);
494	  orig = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 1),
495						   (base == reg ? 0 : reg));
496	}
497      else
498	return orig;
499
500      if (MACHOPIC_PURE && GET_CODE (orig) == CONST_INT)
501	result = plus_constant (base, INTVAL (orig));
502      else
503	result = gen_rtx (PLUS, Pmode, base, orig);
504
505      if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
506	RTX_UNCHANGING_P (result) = 1;
507
508      if (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM)
509	{
510	  if (reg)
511	    {
512	      emit_move_insn (reg, result);
513	      result = reg;
514	    }
515	  else
516	    {
517	      result = force_reg (GET_MODE (result), result);
518	    }
519	}
520
521      return result;
522
523    }
524  else if (GET_CODE (orig) == MEM)
525    XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg);
526  /* When the target is i386, this code prevents crashes due to the
527     compiler's ignorance on how to move the PIC base register to
528     other registers.  (The reload phase sometimes introduces such
529     insns.)  */
530  else if (GET_CODE (orig) == PLUS
531	   && GET_CODE (XEXP (orig, 0)) == REG
532	   && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
533#ifdef I386
534	   /* Prevent the same register from being erroneously used
535	      as both the base and index registers.  */
536	   && GET_CODE (XEXP (orig, 1)) == CONST
537#endif
538	   && reg)
539    {
540      emit_move_insn (reg, XEXP (orig, 0));
541      XEXP (ptr_ref, 0) = reg;
542    }
543  return ptr_ref;
544}
545
546/* Transform TARGET (a MEM), which is a function call target, to the
547   corresponding symbol_stub if necessary.  Return a new MEM.  */
548
549rtx
550machopic_indirect_call_target (target)
551     rtx target;
552{
553  if (GET_CODE (target) != MEM)
554    return target;
555
556  if (MACHOPIC_INDIRECT && GET_CODE (XEXP (target, 0)) == SYMBOL_REF)
557    {
558      enum machine_mode mode = GET_MODE (XEXP (target, 0));
559      const char *name = XSTR (XEXP (target, 0), 0);
560
561      /* If the name is already defined, we need do nothing.  */
562      if (name[0] == '!' && name[1] == 'T')
563	return target;
564
565      if (!machopic_name_defined_p (name))
566	{
567	  const char *stub_name = machopic_stub_name (name);
568
569	  XEXP (target, 0) = gen_rtx (SYMBOL_REF, mode, stub_name);
570	  RTX_UNCHANGING_P (target) = 1;
571	}
572    }
573
574  return target;
575}
576
577rtx
578machopic_legitimize_pic_address (orig, mode, reg)
579     rtx orig, reg;
580     enum machine_mode mode;
581{
582  rtx pic_ref = orig;
583
584  if (! MACHOPIC_PURE)
585    return orig;
586
587  /* First handle a simple SYMBOL_REF or LABEL_REF */
588  if (GET_CODE (orig) == LABEL_REF
589      || (GET_CODE (orig) == SYMBOL_REF
590	  ))
591    {
592      /* addr(foo) = &func+(foo-func) */
593      rtx pic_base;
594
595      orig = machopic_indirect_data_reference (orig, reg);
596
597      if (GET_CODE (orig) == PLUS
598	  && GET_CODE (XEXP (orig, 0)) == REG)
599	{
600	  if (reg == 0)
601	    return force_reg (mode, orig);
602
603	  emit_move_insn (reg, orig);
604	  return reg;
605	}
606
607      pic_base = gen_rtx (SYMBOL_REF, Pmode, machopic_function_base_name ());
608
609      if (GET_CODE (orig) == MEM)
610	{
611	  if (reg == 0)
612	    {
613	      if (reload_in_progress)
614		abort ();
615	      else
616		reg = gen_reg_rtx (Pmode);
617	    }
618
619#ifdef HAVE_lo_sum
620	  if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
621	      || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
622	    {
623	      rtx offset = gen_rtx (CONST, Pmode,
624				    gen_rtx (MINUS, Pmode,
625					     XEXP (orig, 0), pic_base));
626#if defined (TARGET_TOC) /* i.e., PowerPC */
627	      /* Generating a new reg may expose opportunities for
628		 common subexpression elimination.  */
629              rtx hi_sum_reg =
630		(reload_in_progress ? reg : gen_reg_rtx (SImode));
631
632	      emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
633				  gen_rtx (PLUS, Pmode,
634					   pic_offset_table_rtx,
635					   gen_rtx (HIGH, Pmode, offset))));
636	      emit_insn (gen_rtx (SET, VOIDmode, reg,
637				  gen_rtx (MEM, GET_MODE (orig),
638					   gen_rtx (LO_SUM, Pmode,
639						    hi_sum_reg, offset))));
640	      pic_ref = reg;
641
642#else
643	      emit_insn (gen_rtx (USE, VOIDmode,
644			      gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)));
645
646	      emit_insn (gen_rtx (SET, VOIDmode, reg,
647				  gen_rtx (HIGH, Pmode,
648					   gen_rtx (CONST, Pmode, offset))));
649	      emit_insn (gen_rtx (SET, VOIDmode, reg,
650				  gen_rtx (LO_SUM, Pmode, reg,
651					   gen_rtx (CONST, Pmode, offset))));
652	      pic_ref = gen_rtx (PLUS, Pmode,
653				 pic_offset_table_rtx, reg);
654#endif
655	    }
656	  else
657#endif  /* HAVE_lo_sum */
658	    {
659	      rtx pic = pic_offset_table_rtx;
660	      if (GET_CODE (pic) != REG)
661		{
662		  emit_move_insn (reg, pic);
663		  pic = reg;
664		}
665#if 0
666	      emit_insn (gen_rtx (USE, VOIDmode,
667				  gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
668#endif
669
670	      pic_ref = gen_rtx (PLUS, Pmode,
671				 pic,
672				 gen_rtx (CONST, Pmode,
673					  gen_rtx (MINUS, Pmode,
674						   XEXP (orig, 0),
675						   pic_base)));
676	    }
677
678#if !defined (TARGET_TOC)
679	  RTX_UNCHANGING_P (pic_ref) = 1;
680	  emit_move_insn (reg, pic_ref);
681	  pic_ref = gen_rtx (MEM, GET_MODE (orig), reg);
682#endif
683	}
684      else
685	{
686
687#ifdef HAVE_lo_sum
688	  if (GET_CODE (orig) == SYMBOL_REF
689	      || GET_CODE (orig) == LABEL_REF)
690	    {
691	      rtx offset = gen_rtx (CONST, Pmode,
692				    gen_rtx (MINUS, Pmode, orig, pic_base));
693#if defined (TARGET_TOC) /* i.e., PowerPC */
694              rtx hi_sum_reg;
695
696	      if (reg == 0)
697		{
698		  if (reload_in_progress)
699		    abort ();
700		  else
701		    reg = gen_reg_rtx (SImode);
702		}
703
704	      hi_sum_reg = reg;
705
706	      emit_insn (gen_rtx (SET, Pmode, hi_sum_reg,
707				  gen_rtx (PLUS, Pmode,
708					   pic_offset_table_rtx,
709					   gen_rtx (HIGH, Pmode, offset))));
710	      emit_insn (gen_rtx (SET, VOIDmode, reg,
711				  gen_rtx (LO_SUM, Pmode,
712					   hi_sum_reg, offset)));
713	      pic_ref = reg;
714#else
715	      emit_insn (gen_rtx (SET, VOIDmode, reg,
716				  gen_rtx (HIGH, Pmode, offset)));
717	      emit_insn (gen_rtx (SET, VOIDmode, reg,
718				  gen_rtx (LO_SUM, Pmode, reg, offset)));
719	      pic_ref = gen_rtx (PLUS, Pmode,
720				 pic_offset_table_rtx, reg);
721#endif
722	    }
723	  else
724#endif  /*  HAVE_lo_sum  */
725	    {
726	      if (GET_CODE (orig) == REG)
727		{
728		  return orig;
729		}
730	      else
731		{
732		  rtx pic = pic_offset_table_rtx;
733		  if (GET_CODE (pic) != REG)
734		    {
735		      emit_move_insn (reg, pic);
736		      pic = reg;
737		    }
738#if 0
739		  emit_insn (gen_rtx (USE, VOIDmode,
740				      pic_offset_table_rtx));
741#endif
742		  pic_ref = gen_rtx (PLUS, Pmode,
743				     pic,
744				     gen_rtx (CONST, Pmode,
745					      gen_rtx (MINUS, Pmode,
746						       orig, pic_base)));
747		}
748	    }
749	}
750
751      RTX_UNCHANGING_P (pic_ref) = 1;
752
753      if (GET_CODE (pic_ref) != REG)
754        {
755          if (reg != 0)
756            {
757              emit_move_insn (reg, pic_ref);
758              return reg;
759            }
760          else
761            {
762              return force_reg (mode, pic_ref);
763            }
764        }
765      else
766        {
767          return pic_ref;
768        }
769    }
770
771  else if (GET_CODE (orig) == SYMBOL_REF)
772    return orig;
773
774  else if (GET_CODE (orig) == PLUS
775	   && (GET_CODE (XEXP (orig, 0)) == MEM
776	       || GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
777	       || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
778	   && XEXP (orig, 0) != pic_offset_table_rtx
779	   && GET_CODE (XEXP (orig, 1)) != REG)
780
781    {
782      rtx base;
783      int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
784
785      base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
786      orig = machopic_legitimize_pic_address (XEXP (orig, 1),
787					      Pmode, (base == reg ? 0 : reg));
788      if (GET_CODE (orig) == CONST_INT)
789	{
790	  pic_ref = plus_constant (base, INTVAL (orig));
791	  is_complex = 1;
792	}
793      else
794	pic_ref = gen_rtx (PLUS, Pmode, base, orig);
795
796      if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
797	RTX_UNCHANGING_P (pic_ref) = 1;
798
799      if (reg && is_complex)
800	{
801	  emit_move_insn (reg, pic_ref);
802	  pic_ref = reg;
803	}
804      /* Likewise, should we set special REG_NOTEs here?  */
805    }
806
807  else if (GET_CODE (orig) == CONST)
808    {
809      return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
810    }
811
812  else if (GET_CODE (orig) == MEM
813	   && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
814    {
815      rtx addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
816
817      addr = gen_rtx (MEM, GET_MODE (orig), addr);
818      RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
819      emit_move_insn (reg, addr);
820      pic_ref = reg;
821    }
822
823  return pic_ref;
824}
825
826
827void
828machopic_finish (asm_out_file)
829     FILE *asm_out_file;
830{
831  tree temp;
832
833  for (temp = machopic_stubs;
834       temp != NULL_TREE;
835       temp = TREE_CHAIN (temp))
836    {
837      const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
838      const char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
839      char *sym;
840      char *stub;
841
842      if (! TREE_USED (temp))
843	continue;
844
845      /* If the symbol is actually defined, we don't need a stub.  */
846      if (sym_name[0] == '!' && sym_name[1] == 'T')
847	continue;
848
849      STRIP_NAME_ENCODING (sym_name, sym_name);
850
851      sym = alloca (strlen (sym_name) + 2);
852      if (sym_name[0] == '*' || sym_name[0] == '&')
853	strcpy (sym, sym_name + 1);
854      else if (sym_name[0] == '-' || sym_name[0] == '+')
855	strcpy (sym, sym_name);
856      else
857	sym[0] = '_', strcpy (sym + 1, sym_name);
858
859      stub = alloca (strlen (stub_name) + 2);
860      if (stub_name[0] == '*' || stub_name[0] == '&')
861	strcpy (stub, stub_name + 1);
862      else
863	stub[0] = '_', strcpy (stub + 1, stub_name);
864
865      machopic_output_stub (asm_out_file, sym, stub);
866    }
867
868  for (temp = machopic_non_lazy_pointers;
869       temp != NULL_TREE;
870       temp = TREE_CHAIN (temp))
871    {
872      char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
873      char *lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
874#if 0
875      tree decl = lookup_name_darwin (TREE_VALUE (temp));
876#endif
877
878      if (! TREE_USED (temp))
879	continue;
880
881      if (machopic_ident_defined_p (TREE_VALUE (temp))
882#if 0 /* add back when we have private externs */
883          || (decl && DECL_PRIVATE_EXTERN (decl))
884#endif
885	  )
886	{
887	  data_section ();
888	  assemble_align (GET_MODE_ALIGNMENT (Pmode));
889	  assemble_label (lazy_name);
890	  assemble_integer (gen_rtx (SYMBOL_REF, Pmode, sym_name),
891			    GET_MODE_SIZE (Pmode),
892			    GET_MODE_ALIGNMENT (Pmode), 1);
893	}
894      else
895	{
896	  machopic_nl_symbol_ptr_section ();
897	  assemble_name (asm_out_file, lazy_name);
898	  fprintf (asm_out_file, ":\n");
899
900	  fprintf (asm_out_file, "\t.indirect_symbol ");
901	  assemble_name (asm_out_file, sym_name);
902	  fprintf (asm_out_file, "\n");
903
904	  assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode),
905			    GET_MODE_ALIGNMENT (Pmode), 1);
906	}
907    }
908}
909
910int
911machopic_operand_p (op)
912     rtx op;
913{
914  if (MACHOPIC_JUST_INDIRECT)
915    {
916      while (GET_CODE (op) == CONST)
917	op = XEXP (op, 0);
918
919      if (GET_CODE (op) == SYMBOL_REF)
920	return machopic_name_defined_p (XSTR (op, 0));
921      else
922	return 0;
923    }
924
925  while (GET_CODE (op) == CONST)
926    op = XEXP (op, 0);
927
928  if (GET_CODE (op) == MINUS
929      && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
930      && GET_CODE (XEXP (op, 1)) == SYMBOL_REF
931      && machopic_name_defined_p (XSTR (XEXP (op, 0), 0))
932      && machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
933      return 1;
934
935#if 0 /*def TARGET_TOC*/ /* i.e., PowerPC */
936  /* Without this statement, the compiler crashes while compiling enquire.c
937     when targetting PowerPC.  It is not known why this code is not needed
938     when targetting other processors.  */
939  else if (GET_CODE (op) == SYMBOL_REF
940	   && (machopic_classify_name (XSTR (op, 0))
941	       == MACHOPIC_DEFINED_FUNCTION))
942    {
943      return 1;
944    }
945#endif
946
947  return 0;
948}
949
950/* This function records whether a given name corresponds to a defined
951   or undefined function or variable, for machopic_classify_ident to
952   use later.  */
953
954void
955darwin_encode_section_info (decl)
956     tree decl;
957{
958  char code = '\0';
959  int defined = 0;
960  rtx sym_ref;
961  const char *orig_str;
962  char *new_str;
963  size_t len, new_len;
964
965  if ((TREE_CODE (decl) == FUNCTION_DECL
966       || TREE_CODE (decl) == VAR_DECL)
967      && !DECL_EXTERNAL (decl)
968      && ((TREE_STATIC (decl)
969	   && (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
970	  || (DECL_INITIAL (decl)
971	      && DECL_INITIAL (decl) != error_mark_node)))
972    defined = 1;
973
974  if (TREE_CODE (decl) == FUNCTION_DECL)
975    code = (defined ? 'T' : 't');
976  else if (TREE_CODE (decl) == VAR_DECL)
977    code = (defined ? 'D' : 'd');
978
979  if (code == '\0')
980    return;
981
982  sym_ref = XEXP (DECL_RTL (decl), 0);
983  orig_str = XSTR (sym_ref, 0);
984  len = strlen (orig_str) + 1;
985
986  if (orig_str[0] == '!')
987    {
988      /* Already encoded; see if we need to change it.  */
989      if (code == orig_str[1])
990	return;
991      /* Yes, tweak a copy of the name and put it in a new string.  */
992      new_str = alloca (len);
993      memcpy (new_str, orig_str, len);
994      new_str[1] = code;
995      XSTR (sym_ref, 0) = ggc_alloc_string (new_str, len);
996    }
997  else
998    {
999      /* Add the encoding.  */
1000      new_len = len + 4;
1001      new_str = alloca (new_len);
1002      new_str[0] = '!';
1003      new_str[1] = code;
1004      new_str[2] = '_';
1005      new_str[3] = '_';
1006      memcpy (new_str + 4, orig_str, len);
1007      XSTR (sym_ref, 0) = ggc_alloc_string (new_str, new_len);
1008    }
1009  /* The non-lazy pointer list may have captured references to the
1010     old encoded name, change them.  */
1011  if (TREE_CODE (decl) == VAR_DECL)
1012    update_non_lazy_ptrs (XSTR (sym_ref, 0));
1013  else
1014    update_stubs (XSTR (sym_ref, 0));
1015}
1016
1017/* Scan the list of non-lazy pointers and update any recorded names whose
1018   stripped name matches the argument.  */
1019
1020static void
1021update_non_lazy_ptrs (name)
1022     const char *name;
1023{
1024  const char *name1, *name2;
1025  tree temp;
1026
1027  STRIP_NAME_ENCODING (name1, name);
1028
1029  for (temp = machopic_non_lazy_pointers;
1030       temp != NULL_TREE;
1031       temp = TREE_CHAIN (temp))
1032    {
1033      char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1034
1035      if (*sym_name == '!')
1036	{
1037	  STRIP_NAME_ENCODING (name2, sym_name);
1038	  if (strcmp (name1, name2) == 0)
1039	    {
1040	      IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
1041	      break;
1042	    }
1043	}
1044    }
1045}
1046
1047/* Function NAME is being defined, and its label has just been output.
1048   If there's already a reference to a stub for this function, we can
1049   just emit the stub label now and we don't bother emitting the stub later. */
1050
1051void
1052machopic_output_possible_stub_label (file, name)
1053     FILE *file;
1054     const char *name;
1055{
1056  tree temp;
1057
1058
1059  /* Ensure we're looking at a section-encoded name.  */
1060  if (name[0] != '!' || (name[1] != 't' && name[1] != 'T'))
1061    return;
1062
1063  for (temp = machopic_stubs;
1064       temp != NULL_TREE;
1065       temp = TREE_CHAIN (temp))
1066    {
1067      const char *sym_name;
1068
1069      sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1070      if (sym_name[0] == '!' && sym_name[1] == 'T'
1071	  && ! strcmp (name+2, sym_name+2))
1072	{
1073	  ASM_OUTPUT_LABEL (file, IDENTIFIER_POINTER (TREE_PURPOSE (temp)));
1074	  /* Avoid generating a stub for this.  */
1075	  TREE_USED (temp) = 0;
1076	  break;
1077	}
1078    }
1079}
1080
1081/* Scan the list of stubs and update any recorded names whose
1082   stripped name matches the argument.  */
1083
1084static void
1085update_stubs (name)
1086     const char *name;
1087{
1088  const char *name1, *name2;
1089  tree temp;
1090
1091  STRIP_NAME_ENCODING (name1, name);
1092
1093  for (temp = machopic_stubs;
1094       temp != NULL_TREE;
1095       temp = TREE_CHAIN (temp))
1096    {
1097      char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1098
1099      if (*sym_name == '!')
1100	{
1101	  STRIP_NAME_ENCODING (name2, sym_name);
1102	  if (strcmp (name1, name2) == 0)
1103	    {
1104	      IDENTIFIER_POINTER (TREE_VALUE (temp)) = name;
1105	      break;
1106	    }
1107	}
1108    }
1109}
1110
1111void
1112machopic_asm_out_constructor (symbol, priority)
1113     rtx symbol;
1114     int priority ATTRIBUTE_UNUSED;
1115{
1116  if (flag_pic)
1117    mod_init_section ();
1118  else
1119    constructor_section ();
1120  assemble_align (POINTER_SIZE);
1121  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1122
1123  if (!flag_pic)
1124    fprintf (asm_out_file, ".reference .constructors_used\n");
1125}
1126
1127void
1128machopic_asm_out_destructor (symbol, priority)
1129     rtx symbol;
1130     int priority ATTRIBUTE_UNUSED;
1131{
1132  if (flag_pic)
1133    mod_term_section ();
1134  else
1135    destructor_section ();
1136  assemble_align (POINTER_SIZE);
1137  assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1138
1139  if (!flag_pic)
1140    fprintf (asm_out_file, ".reference .destructors_used\n");
1141}
1142